├── .github ├── ISSUE_TEMPLATE │ └── trial-request.md └── workflows │ ├── android-build.yml │ ├── docker-release.yml │ ├── ios-build.yml │ ├── linux-build.yml │ ├── macos-m1-build-sign.yml │ ├── macos-m1-build.yml │ ├── macos-m1-debug.yml │ ├── macos-x64-build.yml │ ├── release.yml │ ├── windows-auth-build.yml │ ├── windows-build.yml │ └── windows-debug.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── agent ├── api.js ├── apps.js ├── apps │ └── ztm │ │ ├── chat │ │ ├── api.js │ │ ├── cli.js │ │ └── main.js │ │ ├── cloud │ │ ├── api.js │ │ ├── cli.js │ │ ├── main.js │ │ └── mime.js │ │ ├── file │ │ ├── api.js │ │ ├── cli.js │ │ └── main.js │ │ ├── llm │ │ ├── api.js │ │ ├── cli.js │ │ └── main.js │ │ ├── port │ │ ├── api.js │ │ ├── cli.js │ │ └── main.js │ │ ├── proxy │ │ ├── api.js │ │ ├── cert-gen.js │ │ ├── cli.js │ │ └── main.js │ │ ├── script │ │ ├── api.js │ │ ├── cli.js │ │ └── main.js │ │ ├── terminal │ │ ├── api.js │ │ ├── cli.js │ │ └── main.js │ │ ├── tunnel │ │ ├── api.js │ │ ├── cli.js │ │ └── main.js │ │ └── users │ │ ├── api.js │ │ ├── cli.js │ │ └── main.js ├── cmdline.js ├── db.js ├── fs.js ├── main.js ├── mesh.js └── service.js ├── build-cli-only.cmd ├── build-cli-only.sh ├── build.cmd ├── build.sh ├── build ├── deps.cmd ├── deps.sh ├── docker │ ├── Dockerfile │ ├── agent-docker-entrypoint.sh │ └── hub-docker-entrypoint.sh ├── gui.cmd ├── gui.sh ├── iOS.sh ├── pipy.cmd └── pipy.sh ├── ca ├── cmdline.js └── main.js ├── cli ├── ca.js ├── client.js ├── cmdline.js ├── db.js └── main.js ├── docs ├── Agent-API.md ├── Architecture-Concepts.md ├── Architecture-Concepts_zh.md ├── Build.md ├── CLI.md ├── CLI_zh.md ├── How-to-LLM.md ├── ZT-App.md └── ZT-App_zh.md ├── gui ├── .env ├── .env.development ├── .eslintrc.cjs ├── .gitignore ├── .prettierrc.json ├── .vscode │ └── extensions.json ├── README.md ├── apps │ └── ztm │ │ ├── cloud │ │ ├── App.vue │ │ ├── bootstrap.js │ │ ├── index.html │ │ ├── main.js │ │ ├── public │ │ │ └── favicon.ico │ │ ├── router │ │ │ ├── config.js │ │ │ ├── guards.js │ │ │ ├── index.js │ │ │ └── main.js │ │ ├── service │ │ │ └── FileService.js │ │ ├── store │ │ │ ├── index.js │ │ │ └── modules │ │ │ │ ├── app.js │ │ │ │ └── index.js │ │ ├── views │ │ │ ├── Config.vue │ │ │ ├── Files.vue │ │ │ ├── Main.vue │ │ │ ├── Preview.vue │ │ │ └── Queue.vue │ │ └── vite.config.js │ │ ├── llm │ │ ├── App.vue │ │ ├── bootstrap.js │ │ ├── index.html │ │ ├── main.js │ │ ├── public │ │ │ └── favicon.ico │ │ ├── router │ │ │ ├── config.js │ │ │ ├── guards.js │ │ │ ├── index.js │ │ │ └── main.js │ │ ├── service │ │ │ └── LLMService.js │ │ ├── store │ │ │ ├── index.js │ │ │ └── modules │ │ │ │ ├── app.js │ │ │ │ └── index.js │ │ ├── views │ │ │ ├── Main.vue │ │ │ └── Setting.vue │ │ └── vite.config.js │ │ ├── proxy │ │ ├── App.vue │ │ ├── bootstrap.js │ │ ├── index.html │ │ ├── main.js │ │ ├── public │ │ │ └── favicon.ico │ │ ├── router │ │ │ ├── config.js │ │ │ ├── guards.js │ │ │ ├── index.js │ │ │ └── main.js │ │ ├── service │ │ │ └── ProxyService.js │ │ ├── store │ │ │ ├── index.js │ │ │ └── modules │ │ │ │ ├── app.js │ │ │ │ └── index.js │ │ ├── views │ │ │ ├── Editor.vue │ │ │ └── Main.vue │ │ └── vite.config.js │ │ ├── script │ │ ├── .gitignore │ │ ├── App.vue │ │ ├── bootstrap.js │ │ ├── index.html │ │ ├── main.js │ │ ├── public │ │ │ ├── favicon.ico │ │ │ ├── scriptList.json │ │ │ └── scripts │ │ │ │ ├── http.js │ │ │ │ ├── ping.js │ │ │ │ └── scan.js │ │ ├── router │ │ │ ├── config.js │ │ │ ├── guards.js │ │ │ ├── index.js │ │ │ └── main.js │ │ ├── service │ │ │ └── ScriptService.js │ │ ├── store │ │ │ ├── index.js │ │ │ └── modules │ │ │ │ ├── app.js │ │ │ │ └── index.js │ │ ├── views │ │ │ ├── Editor.vue │ │ │ ├── Main.vue │ │ │ ├── Result.vue │ │ │ └── Scripts.vue │ │ └── vite.config.js │ │ └── tunnel │ │ ├── App.vue │ │ ├── bootstrap.js │ │ ├── index.html │ │ ├── main.js │ │ ├── public │ │ └── favicon.ico │ │ ├── router │ │ ├── config.js │ │ ├── guards.js │ │ ├── index.js │ │ └── main.js │ │ ├── service │ │ └── TunnelService.js │ │ ├── store │ │ ├── index.js │ │ └── modules │ │ │ ├── app.js │ │ │ └── index.js │ │ ├── views │ │ ├── Main.vue │ │ ├── TunnelEditor.vue │ │ └── Tunnels.vue │ │ └── vite.config.js ├── index.html ├── package.json ├── public │ ├── apps │ │ ├── baidu.json │ │ ├── github.json │ │ ├── gpt.json │ │ ├── huggingface.json │ │ └── migu.json │ ├── favicon.ico │ ├── tauri.svg │ └── vite.svg ├── splashscreen.html ├── src-android │ ├── .gitignore │ └── app │ │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ └── copy.md │ │ ├── java │ │ └── com │ │ │ └── flomesh │ │ │ └── ztm │ │ │ ├── BootReceiver.kt │ │ │ ├── CopyBinaryActivity.kt │ │ │ ├── FileHelper.kt │ │ │ ├── FloatingWindowService.kt │ │ │ ├── MainActivity.kt │ │ │ ├── ReceiveFileActivity.kt │ │ │ └── SAFActivity.kt │ │ └── res │ │ ├── drawable │ │ ├── close.png │ │ ├── gradient_background.xml │ │ ├── ic_launcher.png │ │ ├── loading.png │ │ └── white.png │ │ ├── layout │ │ └── layout_floating_window.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ └── xml │ │ ├── file_paths.xml │ │ └── network_security_config.xml ├── src-ios │ ├── .gitignore │ ├── apple │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── AppIcon-20x20@1x.png │ │ │ │ ├── AppIcon-20x20@2x-1.png │ │ │ │ ├── AppIcon-20x20@2x.png │ │ │ │ ├── AppIcon-20x20@3x.png │ │ │ │ ├── AppIcon-29x29@1x.png │ │ │ │ ├── AppIcon-29x29@2x-1.png │ │ │ │ ├── AppIcon-29x29@2x.png │ │ │ │ ├── AppIcon-29x29@3x.png │ │ │ │ ├── AppIcon-40x40@1x.png │ │ │ │ ├── AppIcon-40x40@2x-1.png │ │ │ │ ├── AppIcon-40x40@2x.png │ │ │ │ ├── AppIcon-40x40@3x.png │ │ │ │ ├── AppIcon-512@2x.png │ │ │ │ ├── AppIcon-60x60@2x.png │ │ │ │ ├── AppIcon-60x60@3x.png │ │ │ │ ├── AppIcon-76x76@1x.png │ │ │ │ ├── AppIcon-76x76@2x.png │ │ │ │ └── AppIcon-83.5x83.5@2x.png │ │ │ └── Contents.json │ │ ├── ExportOptions.plist │ │ ├── Logo.png │ │ ├── Podfile │ │ ├── PrivacyInfo.xcprivacy │ │ ├── RunnerWidget │ │ │ ├── Assets.xcassets │ │ │ │ ├── AccentColor.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── AppIcon.appiconset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ ├── ShareAppIcon.imageset │ │ │ │ │ ├── AppIcon-20x20@1x.png │ │ │ │ │ ├── AppIcon-20x20@2x.png │ │ │ │ │ ├── AppIcon-20x20@3x.png │ │ │ │ │ └── Contents.json │ │ │ │ └── WidgetBackground.colorset │ │ │ │ │ └── Contents.json │ │ │ ├── Info.plist │ │ │ ├── RunnerWidget.swift │ │ │ ├── RunnerWidgetBundle.swift │ │ │ └── RunnerWidgetLiveActivity.swift │ │ ├── RunnerWidgetExtension.entitlements │ │ ├── ShareExtension │ │ │ ├── Base.lproj │ │ │ │ └── MainInterface.storyboard │ │ │ ├── Info.plist │ │ │ ├── ShareExtension.entitlements │ │ │ └── ShareViewController.swift │ │ ├── Sources │ │ │ └── ztm │ │ │ │ ├── ActivityHelper.swift │ │ │ │ ├── LocationManager.swift │ │ │ │ ├── bindings │ │ │ │ └── bindings.h │ │ │ │ ├── main.mm │ │ │ │ └── ztm_iOS-Bridging-Header.h │ │ ├── project.yml │ │ ├── ztm.xcodeproj │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ ├── xcshareddata │ │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ │ └── WorkspaceSettings.xcsettings │ │ │ │ └── xcuserdata │ │ │ │ │ └── lindongchen.xcuserdatad │ │ │ │ │ └── UserInterfaceState.xcuserstate │ │ │ ├── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ │ ├── RunnerWidgetExtension.xcscheme │ │ │ │ │ ├── ShareExtension.xcscheme │ │ │ │ │ └── ztm_iOS.xcscheme │ │ │ └── xcuserdata │ │ │ │ └── lindongchen.xcuserdatad │ │ │ │ └── xcschemes │ │ │ │ └── xcschememanagement.plist │ │ └── ztm_iOS │ │ │ ├── Info.plist │ │ │ └── ztm_iOS.entitlements │ ├── bak │ │ ├── InAppPayHandler.mm │ │ ├── LaunchScreen.storyboard │ │ ├── ProxyHelper.swift │ │ ├── ProxyWidget │ │ │ ├── AppProxyProvider.swift │ │ │ ├── Info.plist │ │ │ └── ProxyWidget.entitlements │ │ ├── ShareHandler.mm │ │ ├── copy.mm │ │ └── main.mm │ ├── ios.md │ ├── projectbak │ ├── setup_lib.sh │ └── sign.sh ├── src-plugin │ └── .gitignore ├── src-tauri │ ├── .gitignore │ ├── Cargo.toml │ ├── Entitlements.plist │ ├── Info.plist │ ├── bin │ │ └── .gitignore │ ├── build.rs │ ├── capabilities │ │ ├── help.md │ │ ├── main.json │ │ └── windows.json │ ├── icons │ │ ├── 128x128.png │ │ ├── 128x128@2x.png │ │ ├── 32x32.png │ │ ├── Square107x107Logo.png │ │ ├── Square142x142Logo.png │ │ ├── Square150x150Logo.png │ │ ├── Square284x284Logo.png │ │ ├── Square30x30Logo.png │ │ ├── Square310x310Logo.png │ │ ├── Square44x44Logo.png │ │ ├── Square71x71Logo.png │ │ ├── Square89x89Logo.png │ │ ├── StoreLogo.png │ │ ├── background.png │ │ ├── icon.icns │ │ ├── icon.ico │ │ ├── icon.png │ │ └── icon2.icns │ ├── scripts │ │ ├── proxy-linux.sh │ │ ├── proxy-mac.sh │ │ ├── proxy-win.cmd │ │ └── proxy-win2.ps1 │ ├── src │ │ ├── bak.rs │ │ ├── binary.rs │ │ ├── browser.rs │ │ ├── lib.rs │ │ ├── main.rs │ │ ├── pay.rs │ │ └── store.rs │ ├── tauri.android.conf.json │ ├── tauri.conf.json │ ├── tauri.ios.conf.json │ ├── tauri.macos.conf.json │ └── tauri.windows.conf.json ├── src │ ├── App.vue │ ├── assets │ │ ├── broswer.scss │ │ ├── iconfont.css │ │ ├── img │ │ │ ├── apps │ │ │ │ ├── appstore.png │ │ │ │ ├── browser.png │ │ │ │ ├── chat.png │ │ │ │ ├── cloud.png │ │ │ │ ├── console.png │ │ │ │ ├── default.png │ │ │ │ ├── ep.png │ │ │ │ ├── ep2.png │ │ │ │ ├── eplog.png │ │ │ │ ├── llm.png │ │ │ │ ├── mesh.png │ │ │ │ ├── proxy.png │ │ │ │ ├── rdp.png │ │ │ │ ├── script.png │ │ │ │ ├── script2.png │ │ │ │ ├── setting.png │ │ │ │ ├── shortcut.png │ │ │ │ ├── terminal.png │ │ │ │ ├── tunnel.png │ │ │ │ ├── users.png │ │ │ │ └── ztmlog.png │ │ │ ├── asset-access.svg │ │ │ ├── asset-error.svg │ │ │ ├── black.svg │ │ │ ├── bot.png │ │ │ ├── bot.svg │ │ │ ├── files │ │ │ │ ├── excel.png │ │ │ │ ├── file.png │ │ │ │ ├── folder.png │ │ │ │ ├── img.png │ │ │ │ ├── img2.png │ │ │ │ ├── mirror.png │ │ │ │ ├── mp3.png │ │ │ │ ├── mp4.png │ │ │ │ ├── pdf.png │ │ │ │ ├── ppt.png │ │ │ │ ├── share.png │ │ │ │ ├── txt.png │ │ │ │ ├── userfolder.png │ │ │ │ ├── word.png │ │ │ │ ├── zip.png │ │ │ │ └── zip2.png │ │ │ ├── free.svg │ │ │ ├── gpt.png │ │ │ ├── hover-web-logo.png │ │ │ ├── lg-black.svg │ │ │ ├── lg-white2.svg │ │ │ ├── llm │ │ │ │ └── deepseek.png │ │ │ ├── loading.png │ │ │ ├── logo-error.svg │ │ │ ├── logo-orange.svg │ │ │ ├── logo.png │ │ │ ├── logo.svg │ │ │ ├── mcp │ │ │ │ ├── excel.png │ │ │ │ ├── github.png │ │ │ │ ├── mcp.png │ │ │ │ └── mcp2.png │ │ │ ├── pipy-white.png │ │ │ ├── pipy.svg │ │ │ ├── service.png │ │ │ ├── startup.svg │ │ │ ├── system.png │ │ │ ├── user.png │ │ │ ├── vue.svg │ │ │ ├── web-logo.png │ │ │ ├── white.png │ │ │ └── white.svg │ │ ├── layout │ │ │ ├── _config.scss │ │ │ ├── _content.scss │ │ │ ├── _footer.scss │ │ │ ├── _main.scss │ │ │ ├── _menu.scss │ │ │ ├── _mixins.scss │ │ │ ├── _preloading.scss │ │ │ ├── _responsive.scss │ │ │ ├── _topbar.scss │ │ │ ├── _typography.scss │ │ │ ├── _utils.scss │ │ │ ├── _variables.scss │ │ │ ├── layout.scss │ │ │ └── theme.scss │ │ ├── styles.scss │ │ ├── svg.css │ │ ├── svg │ │ │ ├── apps.svg │ │ │ ├── back.svg │ │ │ ├── chat.svg │ │ │ ├── cloud.svg │ │ │ ├── endpoint.svg │ │ │ ├── grid.svg │ │ │ ├── home.svg │ │ │ ├── log.svg │ │ │ ├── mesh.svg │ │ │ └── network.svg │ │ └── vue.svg │ ├── bootstrap.js │ ├── components.js │ ├── components │ │ ├── BlockViewer.vue │ │ ├── ChipList.vue │ │ ├── ChipMap.vue │ │ ├── Loading.vue │ │ ├── Status.vue │ │ ├── common │ │ │ ├── AppHeader.vue │ │ │ ├── Avatar.vue │ │ │ ├── BaseCard.vue │ │ │ ├── Card.vue │ │ │ ├── CertificateUploder.vue │ │ │ ├── DataViewLayoutOptions.vue │ │ │ ├── DrawMenu.vue │ │ │ ├── Empty.vue │ │ │ ├── Ep.vue │ │ │ ├── EpSelector.vue │ │ │ ├── FileFolderSelector.vue │ │ │ ├── FileImportSelector.vue │ │ │ ├── FilePreview.vue │ │ │ ├── FileUploderSmall.vue │ │ │ ├── FloatField.vue │ │ │ ├── FormItem.vue │ │ │ ├── HiddenField.vue │ │ │ ├── InputList.vue │ │ │ └── UserSelector.vue │ │ ├── editor │ │ │ ├── JsEditor.vue │ │ │ ├── JsonEditor.vue │ │ │ ├── Monacoeditor.vue │ │ │ └── ShellEditor.vue │ │ ├── mesh │ │ │ ├── MeshSelector.vue │ │ │ └── PipyVersion.vue │ │ └── share │ │ │ ├── Forward.vue │ │ │ ├── Targets.vue │ │ │ └── WatchShared.vue │ ├── directives.js │ ├── directives │ │ └── longtap.js │ ├── doms │ │ └── AcceptFile.js │ ├── i18n │ │ ├── en.json │ │ ├── index.js │ │ └── zh.json │ ├── layout │ │ ├── AppBottombar.vue │ │ ├── AppFooter.vue │ │ ├── AppLayout.vue │ │ ├── AppMenu.vue │ │ ├── AppMenuItem.vue │ │ ├── AppRoot.vue │ │ ├── AppSidebar.vue │ │ ├── AppSmallMenu.vue │ │ ├── AppTopbar.vue │ │ ├── EmptyLayout.vue │ │ ├── composables │ │ │ └── layout.js │ │ └── menu.js │ ├── main.js │ ├── router │ │ ├── config.js │ │ ├── guards.js │ │ ├── index.js │ │ └── modules │ │ │ ├── app.js │ │ │ └── mesh.js │ ├── rules │ │ ├── index.js │ │ └── reg.js │ ├── service │ │ ├── AppService.js │ │ ├── BotService.js │ │ ├── ChatService.js │ │ ├── MCPService.js │ │ ├── ShellService.js │ │ ├── SqlService.js │ │ ├── UsersService.js │ │ ├── ZtmService.js │ │ └── common │ │ │ ├── authority-utils.js │ │ │ ├── axios-interceptors.js │ │ │ ├── cookie.js │ │ │ └── request.js │ ├── store │ │ ├── index.js │ │ └── modules │ │ │ ├── account.js │ │ │ ├── blob.js │ │ │ ├── index.js │ │ │ ├── mcp.js │ │ │ └── notice.js │ ├── theme.js │ ├── utils │ │ ├── app-store.js │ │ ├── clipboard.js │ │ ├── confirm.js │ │ ├── dayjs.js │ │ ├── file.js │ │ ├── localStore.js │ │ ├── mime.js │ │ ├── notification.js │ │ ├── pay.js │ │ ├── platform.js │ │ ├── store.js │ │ ├── style.js │ │ ├── svgAvatar.js │ │ ├── toast.js │ │ ├── webview.js │ │ └── window.js │ └── views │ │ ├── apps │ │ ├── AppManage.vue │ │ ├── AppStore.vue │ │ ├── Apps.vue │ │ └── core │ │ │ ├── Browser.vue │ │ │ ├── RDP.vue │ │ │ ├── Setting.vue │ │ │ ├── TermContent.vue │ │ │ └── ZtmLog.vue │ │ ├── chat │ │ ├── BotChat.vue │ │ ├── BotSetting.vue │ │ ├── Chat.vue │ │ ├── History.vue │ │ ├── Main.vue │ │ └── Setting.vue │ │ ├── log │ │ ├── AppLog.vue │ │ ├── EpLog.vue │ │ └── Log.vue │ │ ├── mesh │ │ ├── EndpointDetail.vue │ │ ├── EndpointInfo.vue │ │ ├── Endpoints.vue │ │ ├── MeshJoin.vue │ │ ├── Meshes.vue │ │ └── Trial.vue │ │ ├── others │ │ ├── Backends.vue │ │ └── Documentation.vue │ │ └── pages │ │ ├── NotFound.vue │ │ └── auth │ │ ├── Access.vue │ │ ├── Error.vue │ │ └── Login.vue └── vite.config.js └── hub ├── ca.js ├── cmdline.js ├── db.js ├── main.js └── options.js /.github/ISSUE_TEMPLATE/trial-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Trial Request 3 | about: Create ticket to setup a free trial ztm on aws 4 | title: Trial Request 5 | labels: '' 6 | assignees: caishu97 7 | 8 | --- 9 | 10 | Thanks to AWS sponsoring free ec2, ztm can now provide a free trial environment. Leave your contact information, or email to support@flomesh.io, or contact us on slack channel https://flomesh-io.slack.com/archives/C070MPVAWP9 . We will configure a free cloud host for ZTM trial for you, and assist you setup ZTM endpoint . 11 | -------------------------------------------------------------------------------- /.github/workflows/ios-build.yml: -------------------------------------------------------------------------------- 1 | name: ios-build 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | build: 7 | runs-on: macos-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: actions/setup-node@v4 11 | with: 12 | node-version: '22' 13 | - name: Decode and import certificate 14 | env: 15 | MACOS_BASE64: ${{ secrets.MACOS_BASE64 }} 16 | MACOS_PASSWORD: ${{ secrets.MACOS_PASSWORD }} 17 | run: | 18 | echo "$MACOS_BASE64" | base64 --decode > certificate.p12 19 | security create-keychain -p actions temp.keychain 20 | security import certificate.p12 -k temp.keychain -P "$MACOS_PASSWORD" -T /usr/bin/codesign 21 | security list-keychains -d user -s temp.keychain 22 | security unlock-keychain -p actions temp.keychain 23 | security set-key-partition-list -S apple-tool:,apple: -s -k actions temp.keychain 24 | - name: Build child app 25 | run: | 26 | cd gui 27 | yarn install 28 | yarn build:apps 29 | - name: Build ztm 30 | run: | 31 | cd gui 32 | yarn build-ztm-ios 33 | - name: Build ipa 34 | run: | 35 | cd gui 36 | yarn ios-init 37 | NODE_OPTIONS="--max-old-space-size=4096" yarn ios-build 38 | - name: sign 39 | env: 40 | APPLE_ID: ${{ secrets.APPLE_ID }} 41 | APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} 42 | run: | 43 | cd gui 44 | src-ios/sign.sh src-tauri/gen/apple/build/arm64/ztm.ipa $APPLE_ID $APPLE_PASSWORD 45 | timeout-minutes: 120 46 | - uses: actions/upload-artifact@v4 47 | with: 48 | name: release 49 | path: ./gui/src-tauri/gen/apple/build/arm64/ztm.ipa 50 | -------------------------------------------------------------------------------- /.github/workflows/macos-m1-build-sign.yml: -------------------------------------------------------------------------------- 1 | name: macos-m1-build-sign 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | build: 7 | runs-on: macos-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: actions/setup-node@v4 11 | with: 12 | node-version: '22' 13 | - name: Decode and import certificate 14 | env: 15 | MACOS_BASE64: ${{ secrets.MACOS_BASE64 }} 16 | MACOS_PASSWORD: ${{ secrets.MACOS_PASSWORD }} 17 | run: | 18 | echo "$MACOS_BASE64" | base64 --decode > certificate.p12 19 | security create-keychain -p actions temp.keychain 20 | security import certificate.p12 -k temp.keychain -P "$MACOS_PASSWORD" -T /usr/bin/codesign 21 | security list-keychains -d user -s temp.keychain 22 | security unlock-keychain -p actions temp.keychain 23 | security set-key-partition-list -S apple-tool:,apple: -s -k actions temp.keychain 24 | - name: build app 25 | run: | 26 | cd gui 27 | yarn install 28 | NODE_OPTIONS="--max-old-space-size=4096" yarn build:apps 29 | yarn build-ztm-macos 30 | NODE_OPTIONS="--max-old-space-size=4096" yarn build:base 31 | - name: sign 32 | env: 33 | APPLE_ID: ${{ secrets.APPLE_ID }} 34 | APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} 35 | run: | 36 | cd gui 37 | src-ios/sign.sh src-tauri/target/release/bundle/dmg/ztm_${{ vars.APP_VERSION }}_aarch64.dmg $APPLE_ID $APPLE_PASSWORD 38 | timeout-minutes: 120 39 | - uses: actions/upload-artifact@v4 40 | with: 41 | name: release 42 | path: ./gui/src-tauri/target/release/bundle/dmg/ztm_${{ vars.APP_VERSION }}_aarch64_signed.dmg 43 | -------------------------------------------------------------------------------- /.github/workflows/macos-m1-build.yml: -------------------------------------------------------------------------------- 1 | name: macos-m1-build 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | build: 7 | runs-on: macos-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: actions/setup-node@v4 11 | with: 12 | node-version: '22' 13 | - name: build app 14 | run: | 15 | cd gui 16 | yarn install 17 | NODE_OPTIONS="--max-old-space-size=4096" yarn build:apps 18 | git fetch --tags 19 | yarn build-ztm-macos 20 | NODE_OPTIONS="--max-old-space-size=4096" yarn build:base 21 | 22 | - name: Rename 23 | run: mv ./gui/src-tauri/target/release/bundle/dmg/ztm_${{ vars.APP_VERSION }}_aarch64.dmg ./gui/src-tauri/target/release/bundle/dmg/ztm-app-v${{ vars.APP_VERSION }}-macos-arm64.dmg 24 | 25 | - uses: actions/upload-artifact@v4 26 | with: 27 | name: ztm-app-v${{ vars.APP_VERSION }}-macos-arm64 28 | path: ./gui/src-tauri/target/release/bundle/dmg/ztm-app-v${{ vars.APP_VERSION }}-macos-arm64.dmg 29 | -------------------------------------------------------------------------------- /.github/workflows/macos-m1-debug.yml: -------------------------------------------------------------------------------- 1 | name: macos-m1-debug 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | build: 7 | runs-on: macos-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: actions/setup-node@v4 11 | with: 12 | node-version: '22' 13 | - name: build app 14 | run: | 15 | cd gui 16 | yarn install 17 | NODE_OPTIONS="--max-old-space-size=4096" yarn build:apps 18 | git fetch --tags 19 | yarn build-ztm-macos 20 | NODE_OPTIONS="--max-old-space-size=4096" yarn build:debug 21 | 22 | - name: Rename 23 | run: mv ./gui/src-tauri/target/debug/bundle/dmg/ztm_${{ vars.APP_VERSION }}_aarch64.dmg ./gui/src-tauri/target/debug/bundle/dmg/ztm-app-v${{ vars.APP_VERSION }}-macos-arm64.dmg 24 | 25 | - uses: actions/upload-artifact@v4 26 | with: 27 | name: ztm-app-v${{ vars.APP_VERSION }}-macos-arm64 28 | path: ./gui/src-tauri/target/debug/bundle/dmg/ztm-app-v${{ vars.APP_VERSION }}-macos-arm64.dmg 29 | -------------------------------------------------------------------------------- /.github/workflows/macos-x64-build.yml: -------------------------------------------------------------------------------- 1 | name: macos-x64-build 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | build: 7 | runs-on: macos-13 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: actions/setup-node@v4 11 | with: 12 | node-version: '22' 13 | - name: build app 14 | run: | 15 | cd gui 16 | yarn install 17 | NODE_OPTIONS="--max-old-space-size=4096" yarn build:apps 18 | yarn build-ztm-macos-x64 19 | NODE_OPTIONS="--max-old-space-size=4096" yarn build:base 20 | - uses: actions/upload-artifact@v4 21 | with: 22 | name: release 23 | path: ./gui/src-tauri/target/release/bundle/dmg/ztm_${{ vars.APP_VERSION }}_x64.dmg 24 | -------------------------------------------------------------------------------- /.github/workflows/windows-auth-build.yml: -------------------------------------------------------------------------------- 1 | name: windows-auth-build 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | build: 7 | runs-on: windows-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: Add msbuild to PATH 11 | uses: microsoft/setup-msbuild@v2 12 | with: 13 | msbuild-architecture: x64 14 | - uses: lukka/get-cmake@latest 15 | with: 16 | cmakeVersion: "~3.25.0" # <--= optional, use most recent 3.25.x version 17 | ninjaVersion: "^1.11.1" 18 | - uses: actions/setup-node@v4 19 | with: 20 | node-version: '22' 21 | - run: npm install -g win-node-env 22 | - name: Install NASM 23 | uses: ilammy/setup-nasm@v1 24 | - name: build child app 25 | run: | 26 | cd gui 27 | yarn install 28 | set NODE_OPTIONS=--max_old_space_size=4096 && yarn build:apps 29 | - name: build ztm 30 | run: | 31 | ./build.cmd 32 | copy ./bin/ztm.exe './gui/src-tauri/bin/ztmctl-x86_64-pc-windows-msvc.exe' 33 | - name: build app 34 | run: | 35 | cd gui 36 | $env:NODE_OPTIONS="--max_old_space_size=4096" 37 | $env:VITE_APP_AUTH_URL="${{ vars.APP_AUTH_URL }}" 38 | yarn build:base 39 | 40 | - name: Rename 41 | run: Rename-Item -Path './gui/src-tauri/target/release/bundle/nsis/ztm_${{ vars.APP_VERSION }}_x64-setup.exe' -NewName 'ztm-app-v${{ vars.APP_VERSION }}-win_x86_64.exe' 42 | 43 | - uses: actions/upload-artifact@v4 44 | with: 45 | name: ztm-app-v${{ vars.APP_VERSION }}-win_x86_64 46 | path: ./gui/src-tauri/target/release/bundle/nsis/ztm-app-v${{ vars.APP_VERSION }}-win_x86_64.exe 47 | -------------------------------------------------------------------------------- /.github/workflows/windows-build.yml: -------------------------------------------------------------------------------- 1 | name: windows-build 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | build: 7 | runs-on: windows-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: Add msbuild to PATH 11 | uses: microsoft/setup-msbuild@v2 12 | with: 13 | msbuild-architecture: x64 14 | - uses: lukka/get-cmake@latest 15 | with: 16 | cmakeVersion: "~3.25.0" # <--= optional, use most recent 3.25.x version 17 | ninjaVersion: "^1.11.1" 18 | - uses: actions/setup-node@v4 19 | with: 20 | node-version: '22' 21 | - run: npm install -g win-node-env 22 | - name: Install NASM 23 | uses: ilammy/setup-nasm@v1 24 | - name: build child app 25 | run: | 26 | cd gui 27 | yarn install 28 | set NODE_OPTIONS=--max_old_space_size=4096 && yarn build:apps 29 | - name: build ztm 30 | run: | 31 | ./build.cmd 32 | copy ./bin/ztm.exe './gui/src-tauri/bin/ztmctl-x86_64-pc-windows-msvc.exe' 33 | - name: build app 34 | run: | 35 | cd gui 36 | set NODE_OPTIONS=--max_old_space_size=4096 && yarn build:base 37 | 38 | - name: Rename 39 | run: Rename-Item -Path './gui/src-tauri/target/release/bundle/nsis/ztm_${{ vars.APP_VERSION }}_x64-setup.exe' -NewName 'ztm-app-v${{ vars.APP_VERSION }}-win_x86_64.exe' 40 | 41 | - uses: actions/upload-artifact@v4 42 | with: 43 | name: ztm-app-v${{ vars.APP_VERSION }}-win_x86_64 44 | path: ./gui/src-tauri/target/release/bundle/nsis/ztm-app-v${{ vars.APP_VERSION }}-win_x86_64.exe 45 | -------------------------------------------------------------------------------- /.github/workflows/windows-debug.yml: -------------------------------------------------------------------------------- 1 | name: windows-debug 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | build: 7 | runs-on: windows-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: Add msbuild to PATH 11 | uses: microsoft/setup-msbuild@v2 12 | with: 13 | msbuild-architecture: x64 14 | - uses: lukka/get-cmake@latest 15 | with: 16 | cmakeVersion: "~3.25.0" # <--= optional, use most recent 3.25.x version 17 | ninjaVersion: "^1.11.1" 18 | - uses: actions/setup-node@v4 19 | with: 20 | node-version: '22' 21 | - run: npm install -g win-node-env 22 | - name: Install NASM 23 | uses: ilammy/setup-nasm@v1 24 | - name: build child app 25 | run: | 26 | cd gui 27 | yarn install 28 | set NODE_OPTIONS=--max_old_space_size=4096 && yarn build:apps 29 | - name: build ztm 30 | run: | 31 | ./build.cmd 32 | copy ./bin/ztm.exe './gui/src-tauri/bin/ztmctl-x86_64-pc-windows-msvc.exe' 33 | - name: build app 34 | run: | 35 | cd gui 36 | set NODE_OPTIONS=--max_old_space_size=4096 && yarn build:debug 37 | - uses: actions/upload-artifact@v4 38 | with: 39 | name: release 40 | path: ./gui/src-tauri/target/debug/bundle/nsis/ztm_${{ vars.APP_VERSION }}_x64-setup.exe 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .vscode/ 3 | 4 | bin/ 5 | cli/version.json 6 | hub/version.json 7 | agent/version.json 8 | agent/gui 9 | agent/apps/*/*/gui 10 | version.env 11 | usr/ 12 | data 13 | config.json 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "pipy"] 2 | path = pipy 3 | url = https://github.com/flomesh-io/pipy.git 4 | -------------------------------------------------------------------------------- /agent/apps/ztm/chat/cli.js: -------------------------------------------------------------------------------- 1 | export default function ({ app, mesh, api, utils }) { 2 | return pipeline($=>$ 3 | .onStart(ctx => main(ctx)) 4 | ) 5 | 6 | function main({ argv, cwd, endpoint }) { 7 | var buffer = new Data 8 | 9 | function output(str) { 10 | buffer.push(str) 11 | } 12 | 13 | function error(err) { 14 | output('ztm: ') 15 | output(err.message || err.toString()) 16 | output('\n') 17 | } 18 | 19 | function flush() { 20 | return Promise.resolve([buffer, new StreamEnd]) 21 | } 22 | 23 | try { 24 | return utils.parseArgv(argv, { 25 | help: text => Promise.resolve(output(text + '\n')), 26 | commands: [ 27 | { 28 | }, 29 | ] 30 | 31 | }).then(flush).catch(err => { 32 | error(err) 33 | return flush() 34 | }) 35 | 36 | } catch (err) { 37 | error(err) 38 | return flush() 39 | } 40 | } 41 | } 42 | 43 | function printTable(data, columns) { 44 | var output = new Data 45 | var cols = Object.entries(columns) 46 | var colHeaders = cols.map(i => i[0]) 47 | var colFormats = cols.map(i => i[1]) 48 | var colSizes = colHeaders.map(name => name.length) 49 | var rows = data.map(row => colFormats.map( 50 | (format, i) => { 51 | var v = (format(row) || '').toString() 52 | colSizes[i] = Math.max(colSizes[i], v.length) 53 | return v 54 | } 55 | )) 56 | colHeaders.forEach((name, i) => { 57 | output.push(name.padEnd(colSizes[i])) 58 | output.push(' ') 59 | }) 60 | output.push('\n') 61 | rows.forEach(row => { 62 | row.forEach((v, i) => { 63 | output.push(v.padEnd(colSizes[i])) 64 | output.push(' ') 65 | }) 66 | output.push('\n') 67 | }) 68 | return output 69 | } 70 | -------------------------------------------------------------------------------- /build-cli-only.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | 3 | CD %~dp0 4 | CMD /c "git clean -X -f agent" 5 | 6 | CD %~dp0 7 | CALL build\deps.cmd 8 | CALL build\pipy.cmd 9 | 10 | IF NOT EXIST bin (MD bin) 11 | COPY pipy\bin\Release\pipy.exe bin\ztm.exe 12 | 13 | ECHO The final product is ready at bin\ztm.exe 14 | 15 | if defined PACKAGE_OUTPUT ( 16 | tar.exe -cf ztm-aio-%ZTM_VERSION%-win-x86_64.tar bin\ztm.exe 17 | ) 18 | -------------------------------------------------------------------------------- /build-cli-only.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ZTM_DIR=$(cd "$(dirname "$0")" && pwd) 4 | 5 | cd "$ZTM_DIR" 6 | git clean -X -f agent 7 | 8 | cd "$ZTM_DIR" 9 | build/deps.sh 10 | 11 | if [ $? -ne 0 ]; then 12 | echo "Prepare deps failed, exit..." 13 | exit 1 14 | fi 15 | 16 | cd "$ZTM_DIR" 17 | build/pipy.sh 18 | -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | 3 | CD "%~dp0\gui" 4 | CMD /c "npm install --no-audit" 5 | 6 | CD %~dp0 7 | CALL build\deps.cmd 8 | CALL build\gui.cmd 9 | CALL build\pipy.cmd 10 | 11 | IF NOT EXIST bin (MD bin) 12 | COPY pipy\bin\Release\pipy.exe bin\ztm.exe 13 | 14 | ECHO The final product is ready at bin\ztm.exe 15 | 16 | if defined PACKAGE_OUTPUT ( 17 | tar.exe -cf ztm-aio-%ZTM_VERSION%-win-x86_64.tar bin\ztm.exe 18 | ) 19 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ZTM_DIR=$(cd "$(dirname "$0")" && pwd) 4 | 5 | cd "$ZTM_DIR/gui" 6 | npm install --no-audit 7 | 8 | cd "$ZTM_DIR" 9 | build/deps.sh 10 | 11 | if [ $? -ne 0 ]; then 12 | echo "Prepare deps failed, exit..." 13 | exit 1 14 | fi 15 | 16 | cd "$ZTM_DIR" 17 | build/gui.sh 18 | build/pipy.sh 19 | -------------------------------------------------------------------------------- /build/deps.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | 3 | SET cur_dir=%CD% 4 | 5 | CD %~dp0 6 | CD .. 7 | SET ztm_dir=%CD% 8 | 9 | CD "%ztm_dir%" 10 | CMD /c "git submodule update --init" 11 | 12 | CD "%cur_dir%" 13 | 14 | if exist "hub\cluster.js" ( 15 | set EDITION=Enterprise 16 | ) else ( 17 | set EDITION=Community 18 | ) 19 | 20 | if defined ZTM_VERSION ( 21 | set VERSION=%ZTM_VERSION% 22 | ) else ( 23 | FOR /f %%i IN ('git describe --abbrev^=0 --tags') DO SET VERSION=%%i 24 | ) 25 | 26 | FOR /f %%i IN ('git log -1 --format^=%%H') DO SET COMMIT=%%i 27 | FOR /f "eol= tokens=* delims=" %%i IN ('"git log -1 --format=%%cD"') DO SET COMMIT_DATE=%%i 28 | 29 | ECHO {"edition":"%EDITION%","tag":"%VERSION%","commit":"%COMMIT%","date":"%COMMIT_DATE%"} > cli\version.json 30 | COPY cli\version.json hub\version.json 31 | COPY cli\version.json agent\version.json 32 | -------------------------------------------------------------------------------- /build/deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ZTM_DIR=$(cd "$(dirname "$0")" && cd .. && pwd) 4 | 5 | check_version() { 6 | if [ `printf '%s\n%s' $1 $2 | sort -V | head -n1` = $1 ]; then 7 | echo $3 8 | exit 1 9 | fi 10 | } 11 | 12 | if ! command -v node &> /dev/null 13 | then 14 | echo "Can't find node command, exit..." 15 | exit 1 16 | fi 17 | 18 | check_version `node -v` 'v16' 'Require Node.js version 16 or above' 19 | 20 | cd "$ZTM_DIR" 21 | git submodule update --init 22 | if [ $? -ne 0 ]; then 23 | echo 'Cannot download Pipy from github.com' 24 | exit 1 25 | fi 26 | 27 | cd "$ZTM_DIR" 28 | 29 | if test -e "hub/cluster.js"; then 30 | EDITION="Enterprise" 31 | else 32 | EDITION="Community" 33 | fi 34 | 35 | if [ -n "$ZTM_VERSION" ]; then 36 | VERSION="$ZTM_VERSION" 37 | else 38 | VERSION=`git describe --abbrev=0 --tags` 39 | fi 40 | 41 | COMMIT=`git log -1 --format=%H` 42 | COMMIT_DATE=`git log -1 --format=%cD` 43 | 44 | VERSION_JSON="{ 45 | \"edition\":\"$EDITION\", 46 | \"tag\": \"$VERSION\", 47 | \"commit\": \"$COMMIT\", 48 | \"date\": \"$COMMIT_DATE\" 49 | }" 50 | 51 | echo "$VERSION_JSON" > cli/version.json 52 | echo "$VERSION_JSON" > hub/version.json 53 | echo "$VERSION_JSON" > agent/version.json 54 | 55 | echo "VERSION=\"$VERSION\"" > version.env 56 | echo "COMMIT=\"$COMMIT\"" >> version.env 57 | echo "COMMIT_DATE=\"$COMMIT_DATE\"" >> version.env 58 | -------------------------------------------------------------------------------- /build/docker/agent-docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if required environment variables are set 4 | if [ -z "$ZTM_JOIN_MESH" ]; then 5 | echo "Error: ZTM_JOIN_MESH environment variable is not set." 6 | exit 1 7 | fi 8 | 9 | if [ -z "$ZTM_ENDPOINT" ]; then 10 | echo "Error: ZTM_ENDPOINT environment variable is not set." 11 | exit 1 12 | fi 13 | 14 | # Set default values for optional environment variables 15 | ZTM_PORT=${ZTM_PORT:-7777} 16 | ZTM_PERMIT=${ZTM_PERMIT:-/permit} 17 | 18 | # Run the command 19 | exec /usr/local/bin/ztm run agent --listen 0.0.0.0:$ZTM_PORT --data ${ZTM_DATA} --permit ${ZTM_PERMIT}/ztm-permit.json --join $ZTM_JOIN_MESH --join-as $ZTM_ENDPOINT 20 | -------------------------------------------------------------------------------- /build/docker/hub-docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ZTM_NAMES=${ZTM_NAMES:-0.0.0.0} 4 | ZTM_PORT=${ZTM_PORT:-8888} 5 | 6 | exec /usr/local/bin/ztm run hub --listen 0.0.0.0:${ZTM_PORT} --data ${ZTM_DATA} --names "${ZTM_NAMES}:${ZTM_PORT}" --permit /permit/root.json -------------------------------------------------------------------------------- /build/gui.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | 3 | SET cur_dir=%CD% 4 | 5 | CD %~dp0 6 | CD .. 7 | SET ztm_dir=%CD% 8 | 9 | CD "%ztm_dir%\gui" 10 | CMD /c "npm run build" 11 | CMD /c "npm run build:apps" 12 | 13 | CD "%ztm_dir%\pipy" 14 | IF EXIST build\deps\codebases.tar.gz.h (DEL build\deps\codebases.tar.gz.h) 15 | 16 | CD "%cur_dir%" 17 | -------------------------------------------------------------------------------- /build/gui.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ZTM_DIR=$(cd "$(dirname "$0")" && cd .. && pwd) 4 | 5 | cd "$ZTM_DIR/gui" 6 | npm run build 7 | npm run build:apps 8 | 9 | rm -f "$ZTM_DIR/pipy/build/deps/codebases.tar.gz.h" 10 | -------------------------------------------------------------------------------- /build/pipy.cmd: -------------------------------------------------------------------------------- 1 | @ECHO on 2 | 3 | SET cur_dir=%CD% 4 | 5 | CD %~dp0 6 | CD .. 7 | SET ztm_dir=%CD% 8 | 9 | CD "%ztm_dir%\pipy" 10 | 11 | IF NOT EXIST build (MD build) 12 | 13 | CD build 14 | SET codebases="ztm/ca:../ca,ztm/hub:../hub,ztm/agent:../agent,ztm/cli:../cli" 15 | SET options="repo://ztm/cli --args" 16 | CMD /c "cmake .. -DCMAKE_BUILD_TYPE=Release -DPIPY_GUI=OFF -DPIPY_CODEBASES=ON -DPIPY_SAMPLE_CODEBASES=OFF -DPIPY_CUSTOM_CODEBASES=%codebases% -DPIPY_DEFAULT_OPTIONS=%options%" 17 | CMD /c "msbuild pipy.sln -t:pipy -p:Configuration=Release" 18 | 19 | CD "%cur_dir%" 20 | -------------------------------------------------------------------------------- /gui/.env: -------------------------------------------------------------------------------- 1 | VITE_APP_MODE=base 2 | VITE_APP_API_PORT=7777 3 | VITE_APP_HUB_LISTEN=127.0.0.1:8888 4 | VITE_APP_PUB_HUB=https://ztm-portal.flomesh.io:7779 5 | VITE_APP_AUTH_URL= 6 | VITE_APP_LANG=en -------------------------------------------------------------------------------- /gui/.env.development: -------------------------------------------------------------------------------- 1 | NODE_ENV=development 2 | VITE_APP_MODE=base 3 | VITE_APP_API_PORT=7777 4 | VITE_APP_HUB_LISTEN=127.0.0.1:8888 5 | VITE_APP_AUTH_URL= 6 | VITE_APP_LANG=zh -------------------------------------------------------------------------------- /gui/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | require('@rushstack/eslint-patch/modern-module-resolution'); 3 | 4 | module.exports = { 5 | root: true, 6 | extends: ['plugin:vue/vue3-essential', 'eslint:recommended', '@vue/eslint-config-prettier'], 7 | parserOptions: { 8 | ecmaVersion: 'latest' 9 | }, 10 | rules: { 11 | 'vue/multi-word-component-names': 'off', 12 | 'vue/no-reserved-component-names': 'off', 13 | 'vue/component-tags-order': [ 14 | 'error', 15 | { 16 | order: ['script', 'template', 'style'] 17 | } 18 | ] 19 | } 20 | }; -------------------------------------------------------------------------------- /gui/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | CA.md 10 | android.md 11 | # dependencies 12 | /node_modules 13 | package-lock.json 14 | permit.json 15 | yarn.lock 16 | .DS_Store 17 | dist 18 | dist-ssr 19 | coverage 20 | *.local 21 | /src/sdk 22 | /release 23 | /download/* 24 | /public/demo 25 | /public/login 26 | /agent 27 | /src-tauri/agent 28 | /public/agent 29 | /public/log 30 | /cypress/videos/ 31 | /cypress/screenshots/ 32 | /mock/*.mjs 33 | /src-tauri/target 34 | # Editor directories and files 35 | .vscode/* 36 | !.vscode/extensions.json 37 | .idea 38 | *.suo 39 | *.ntvs* 40 | *.njsproj 41 | *.sln 42 | *.sw? 43 | 44 | # Themes 45 | public/themes/soho-light/ 46 | public/themes/soho-dark/ 47 | public/themes/viva-light/ 48 | public/themes/viva-dark/ 49 | public/themes/mira/ 50 | public/themes/nano/ -------------------------------------------------------------------------------- /gui/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": false, 3 | "tabWidth": 4, 4 | "trailingComma": "none", 5 | "semi": true, 6 | "singleQuote": true, 7 | "vueIndentScriptAndStyle": false, 8 | "printWidth": 250, 9 | "bracketSameLine": false 10 | } -------------------------------------------------------------------------------- /gui/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "Vue.volar", 4 | "tauri-apps.tauri-vscode", 5 | "rust-lang.rust-analyzer" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /gui/README.md: -------------------------------------------------------------------------------- 1 | # ZTM developing with Tauri2.0 + Vue 3 + Vite 2 | 3 | This template should help get you started developing with Tauri2.0 + Vue 3 in Vite. The template uses Vue 3 ` 21 | 22 | -------------------------------------------------------------------------------- /gui/apps/ztm/cloud/bootstrap.js: -------------------------------------------------------------------------------- 1 | import { loadInterceptors } from "@/service/common/request"; 2 | import interceptors from "@/service/common/axios-interceptors"; 3 | import guards from "./router/guards"; 4 | 5 | let appOptions = { 6 | router: undefined, 7 | store: undefined, 8 | }; 9 | 10 | function loadGuards(guards, options) { 11 | const { beforeEach, afterEach } = guards; 12 | const { router } = options; 13 | beforeEach.forEach((guard) => { 14 | if (guard && typeof guard === "function") { 15 | router.beforeEach((to, from, next) => guard(to, from, next, options)); 16 | } 17 | }); 18 | afterEach.forEach((guard) => { 19 | if (guard && typeof guard === "function") { 20 | router.afterEach((to, from) => guard(to, from, options)); 21 | } 22 | }); 23 | } 24 | 25 | function setAppOptions(options) { 26 | const { router, store } = options; 27 | appOptions.router = router; 28 | appOptions.store = store; 29 | } 30 | 31 | function bootstrap({ router, store }) { 32 | setAppOptions({ router, store }); 33 | loadInterceptors(interceptors, { router, store }); 34 | loadGuards(guards, { router, store }); 35 | } 36 | 37 | export default bootstrap; 38 | -------------------------------------------------------------------------------- /gui/apps/ztm/cloud/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Cloud - ZTM 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /gui/apps/ztm/cloud/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | import { initRouter } from "./router"; 4 | import store from "./store"; 5 | import PrimeVue from 'primevue/config'; 6 | import ToastService from 'primevue/toastservice'; 7 | import DialogService from 'primevue/dialogservice'; 8 | import ConfirmationService from 'primevue/confirmationservice'; 9 | import { useComponent } from '@/components'; 10 | import { useDirective } from '@/directives'; 11 | import rulesReg from '@/rules/reg'; 12 | import bootstrap from "./bootstrap"; 13 | import MyPreset from '@/theme'; 14 | import '@/assets/styles.scss'; 15 | import i18n from '@/i18n'; 16 | 17 | const app = createApp(App); 18 | app.use(PrimeVue, { 19 | ripple: true , 20 | theme: { 21 | preset: MyPreset, 22 | options: { 23 | prefix: 'p', 24 | darkModeSelector: 'system', 25 | cssLayer: false 26 | } 27 | } 28 | }); 29 | 30 | app.mixin({ 31 | mounted() { 32 | document.querySelectorAll('button:not(.link)').forEach(button => { 33 | button.addEventListener('click', event => { 34 | event.preventDefault(); 35 | }); 36 | }); 37 | } 38 | }); 39 | 40 | useComponent(app); 41 | useDirective(app); 42 | app.use(store); 43 | app.use(ToastService); 44 | app.use(DialogService); 45 | app.use(ConfirmationService); 46 | app.use(i18n); 47 | 48 | async function setRouter() { 49 | const router = await initRouter({ store }); 50 | app.use(router); 51 | app.mount("#app"); 52 | bootstrap({ router, store }); 53 | } 54 | setRouter(); -------------------------------------------------------------------------------- /gui/apps/ztm/cloud/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/apps/ztm/cloud/public/favicon.ico -------------------------------------------------------------------------------- /gui/apps/ztm/cloud/router/config.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | import main from "./main"; 3 | import EmptyLayout from '@/layout/EmptyLayout.vue'; 4 | 5 | const options = { 6 | routes: [ 7 | { 8 | path: "/:pathMatch(.*)", 9 | name: "404", 10 | component: () => import('@/views/pages/NotFound.vue') 11 | }, 12 | { 13 | path: "/403", 14 | name: "403", 15 | component: () => import('@/views/pages/auth/Access.vue') 16 | }, 17 | { 18 | path: '/error', 19 | name: 'error', 20 | component: () => import('@/views/pages/auth/Error.vue') 21 | }, 22 | { 23 | path: '/', 24 | component: EmptyLayout, 25 | redirect: "/main", 26 | children: [ 27 | main 28 | ] 29 | }, 30 | ], 31 | }; 32 | 33 | options.initRoutes = _.cloneDeep(options.routes); 34 | export default options; 35 | -------------------------------------------------------------------------------- /gui/apps/ztm/cloud/router/guards.js: -------------------------------------------------------------------------------- 1 | import FileService from '../service/FileService'; 2 | import NProgress from "nprogress"; 3 | import "nprogress/nprogress.css"; 4 | import { useToast } from "primevue/usetoast"; 5 | import { useStore } from 'vuex'; 6 | NProgress.configure({ showSpinner: true }); 7 | 8 | const fileService = new FileService(); 9 | 10 | 11 | /** 12 | * Progress Start 13 | * @param to 14 | * @param form 15 | * @param next 16 | */ 17 | const progressStart = (to, from, next) => { 18 | // start progress bar 19 | if (!NProgress.isStarted()) { 20 | NProgress.start(); 21 | } 22 | next(); 23 | }; 24 | 25 | /** 26 | * App Info Guard 27 | * @param to 28 | * @param form 29 | * @param next 30 | * @param options 31 | */ 32 | const infoGuard = (to, from, next, options) => { 33 | const { toast } = options; 34 | const store = useStore(); 35 | const _info = store.getters['app/info']; 36 | if(!!_info){ 37 | next(); 38 | } else { 39 | fileService.getInfo() 40 | .then(res => { 41 | store.commit('app/setInfo', res); 42 | next(); 43 | }) 44 | .catch(err => { 45 | console.log('Request Failed', err); 46 | }); 47 | } 48 | }; 49 | 50 | /** 51 | * Progress Done 52 | * @param to 53 | * @param form 54 | * @param options 55 | */ 56 | const progressDone = () => { 57 | // finish progress bar 58 | NProgress.done(); 59 | }; 60 | 61 | export default { 62 | beforeEach: [ 63 | progressStart, 64 | infoGuard, 65 | ], 66 | afterEach: [progressDone], 67 | }; 68 | -------------------------------------------------------------------------------- /gui/apps/ztm/cloud/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory } from 'vue-router'; 2 | import { isAdmin } from "@/service/common/authority-utils"; 3 | import baseOptions from './config'; 4 | 5 | const loginIgnore = { 6 | names: ["404", "403", "Login", "Root"], 7 | paths: ["/login","/root"], 8 | includes(route) { 9 | return this.names.includes(route.name) || this.paths.includes(route.path); 10 | }, 11 | }; 12 | 13 | function resetRoutes(router, store) { 14 | const options = baseOptions; 15 | if(!!router){ 16 | const oldRoutes = router.getRoutes(); 17 | oldRoutes.forEach((oldRoute) => { 18 | router.removeRoute(oldRoute.name); 19 | }); 20 | options.routes.forEach((newRoute) => { 21 | router.addRoute(newRoute); 22 | }); 23 | } 24 | return options; 25 | } 26 | 27 | async function initRouter({ store }) { 28 | const options = resetRoutes(null, store); 29 | // options.history = createWebHistory(process.env.VUE_APP_PUBLIC_PATH); 30 | options.history = createWebHashHistory(); 31 | return createRouter(options); 32 | } 33 | 34 | export { loginIgnore, initRouter, resetRoutes }; 35 | -------------------------------------------------------------------------------- /gui/apps/ztm/cloud/router/main.js: -------------------------------------------------------------------------------- 1 | const main = { 2 | path: "main", 3 | name: "Main", 4 | redirect: "/main", 5 | children: [ 6 | { 7 | path: '/main', 8 | name: 'files', 9 | component: () => import('../views/Main.vue') 10 | }, 11 | ], 12 | }; 13 | 14 | export default main; 15 | -------------------------------------------------------------------------------- /gui/apps/ztm/cloud/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "vuex"; 2 | import modules from "./modules"; 3 | 4 | const store = createStore({ modules }); 5 | 6 | export default store; 7 | -------------------------------------------------------------------------------- /gui/apps/ztm/cloud/store/modules/app.js: -------------------------------------------------------------------------------- 1 | export default { 2 | namespaced: true, 3 | state: { 4 | info:null, 5 | }, 6 | getters: { 7 | info: (state) => { 8 | return state.info; 9 | }, 10 | }, 11 | mutations: { 12 | setInfo(state, info) { 13 | state.info = info; 14 | }, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /gui/apps/ztm/cloud/store/modules/index.js: -------------------------------------------------------------------------------- 1 | import app from "./app"; 2 | import notice from "@/store/modules/notice"; 3 | 4 | export default { app, notice }; 5 | -------------------------------------------------------------------------------- /gui/apps/ztm/cloud/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url'; 2 | import { defineConfig, loadEnv } from 'vite'; 3 | import vue from '@vitejs/plugin-vue'; 4 | import { resolve } from 'path'; 5 | import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'; 6 | export default defineConfig(async (config) => { 7 | return { 8 | base:"./", 9 | clearScreen: false, 10 | optimizeDeps: { 11 | dynamicImportVars: true, 12 | }, 13 | server: { 14 | port: 1425, 15 | strictPort: true, 16 | proxy: { 17 | '/api': { 18 | target: `http://0.0.0.0:${loadEnv(config.mode, process.cwd()).VITE_APP_API_PORT}/`, 19 | changeOrigin: true, 20 | }, 21 | } 22 | }, 23 | plugins: [ 24 | vue({reactivityTransform: true}), 25 | createSvgIconsPlugin({ 26 | iconDirs: [resolve(process.cwd(), '../../../src/assets/svg')], 27 | symbolId: 'svg-[name]', // 自定义 symbolId 模板 28 | }), 29 | ], 30 | resolve: { 31 | alias: { 32 | '@': fileURLToPath(new URL('../../../src', import.meta.url)) 33 | } 34 | } 35 | } 36 | }); 37 | -------------------------------------------------------------------------------- /gui/apps/ztm/llm/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 21 | 22 | -------------------------------------------------------------------------------- /gui/apps/ztm/llm/bootstrap.js: -------------------------------------------------------------------------------- 1 | import { loadInterceptors } from "@/service/common/request"; 2 | import interceptors from "@/service/common/axios-interceptors"; 3 | import guards from "./router/guards"; 4 | 5 | let appOptions = { 6 | router: undefined, 7 | store: undefined, 8 | }; 9 | 10 | function loadGuards(guards, options) { 11 | const { beforeEach, afterEach } = guards; 12 | const { router } = options; 13 | beforeEach.forEach((guard) => { 14 | if (guard && typeof guard === "function") { 15 | router.beforeEach((to, from, next) => guard(to, from, next, options)); 16 | } 17 | }); 18 | afterEach.forEach((guard) => { 19 | if (guard && typeof guard === "function") { 20 | router.afterEach((to, from) => guard(to, from, options)); 21 | } 22 | }); 23 | } 24 | 25 | function setAppOptions(options) { 26 | const { router, store } = options; 27 | appOptions.router = router; 28 | appOptions.store = store; 29 | } 30 | 31 | function bootstrap({ router, store }) { 32 | setAppOptions({ router, store }); 33 | loadInterceptors(interceptors, { router, store }); 34 | loadGuards(guards, { router, store }); 35 | } 36 | 37 | export default bootstrap; 38 | -------------------------------------------------------------------------------- /gui/apps/ztm/llm/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LLM - ZTM 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /gui/apps/ztm/llm/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | import { initRouter } from "./router"; 4 | import store from "./store"; 5 | import PrimeVue from 'primevue/config'; 6 | import ToastService from 'primevue/toastservice'; 7 | import DialogService from 'primevue/dialogservice'; 8 | import ConfirmationService from 'primevue/confirmationservice'; 9 | import { useComponent } from '@/components'; 10 | import { useDirective } from '@/directives'; 11 | import rulesReg from '@/rules/reg'; 12 | import bootstrap from "./bootstrap"; 13 | import MyPreset from '@/theme'; 14 | import '@/assets/styles.scss'; 15 | import i18n from '@/i18n'; 16 | 17 | const app = createApp(App); 18 | app.use(PrimeVue, { 19 | ripple: true , 20 | theme: { 21 | preset: MyPreset, 22 | options: { 23 | prefix: 'p', 24 | darkModeSelector: 'system', 25 | cssLayer: false 26 | } 27 | } 28 | }); 29 | 30 | app.mixin({ 31 | mounted() { 32 | document.querySelectorAll('button:not(.link)').forEach(button => { 33 | button.addEventListener('click', event => { 34 | event.preventDefault(); 35 | }); 36 | }); 37 | } 38 | }); 39 | 40 | useComponent(app); 41 | useDirective(app); 42 | app.use(store); 43 | app.use(ToastService); 44 | app.use(DialogService); 45 | app.use(ConfirmationService); 46 | app.use(i18n); 47 | 48 | async function setRouter() { 49 | const router = await initRouter({ store }); 50 | app.use(router); 51 | app.mount("#app"); 52 | bootstrap({ router, store }); 53 | } 54 | setRouter(); -------------------------------------------------------------------------------- /gui/apps/ztm/llm/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/apps/ztm/llm/public/favicon.ico -------------------------------------------------------------------------------- /gui/apps/ztm/llm/router/config.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | import main from "./main"; 3 | import EmptyLayout from '@/layout/EmptyLayout.vue'; 4 | 5 | const options = { 6 | routes: [ 7 | { 8 | path: "/:pathMatch(.*)", 9 | name: "404", 10 | component: () => import('@/views/pages/NotFound.vue') 11 | }, 12 | { 13 | path: "/403", 14 | name: "403", 15 | component: () => import('@/views/pages/auth/Access.vue') 16 | }, 17 | { 18 | path: '/error', 19 | name: 'error', 20 | component: () => import('@/views/pages/auth/Error.vue') 21 | }, 22 | { 23 | path: '/', 24 | component: EmptyLayout, 25 | redirect: "/main", 26 | children: [ 27 | main 28 | ] 29 | }, 30 | ], 31 | }; 32 | 33 | options.initRoutes = _.cloneDeep(options.routes); 34 | export default options; 35 | -------------------------------------------------------------------------------- /gui/apps/ztm/llm/router/guards.js: -------------------------------------------------------------------------------- 1 | import LLMService from '../service/LLMService'; 2 | import NProgress from "nprogress"; 3 | import "nprogress/nprogress.css"; 4 | import { useToast } from "primevue/usetoast"; 5 | import { useStore } from 'vuex'; 6 | NProgress.configure({ showSpinner: true }); 7 | 8 | const llmService = new LLMService(); 9 | 10 | 11 | /** 12 | * Progress Start 13 | * @param to 14 | * @param form 15 | * @param next 16 | */ 17 | const progressStart = (to, from, next) => { 18 | // start progress bar 19 | if (!NProgress.isStarted()) { 20 | NProgress.start(); 21 | } 22 | next(); 23 | }; 24 | 25 | /** 26 | * App Info Guard 27 | * @param to 28 | * @param form 29 | * @param next 30 | * @param options 31 | */ 32 | const infoGuard = (to, from, next, options) => { 33 | const { toast } = options; 34 | const store = useStore(); 35 | const _info = store.getters['app/info'] 36 | if(!!_info){ 37 | next(); 38 | } else { 39 | llmService.getInfo() 40 | .then(res => { 41 | next(); 42 | store.commit('app/setInfo', res); 43 | }) 44 | .catch(err => console.log('Request Failed', err)); 45 | } 46 | }; 47 | 48 | /** 49 | * Progress Done 50 | * @param to 51 | * @param form 52 | * @param options 53 | */ 54 | const progressDone = () => { 55 | // finish progress bar 56 | NProgress.done(); 57 | }; 58 | 59 | export default { 60 | beforeEach: [ 61 | progressStart, 62 | infoGuard, 63 | ], 64 | afterEach: [progressDone], 65 | }; 66 | -------------------------------------------------------------------------------- /gui/apps/ztm/llm/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory } from 'vue-router'; 2 | import { isAdmin } from "@/service/common/authority-utils"; 3 | import baseOptions from './config'; 4 | 5 | const loginIgnore = { 6 | names: ["404", "403", "Login", "Root"], 7 | paths: ["/login","/root"], 8 | includes(route) { 9 | return this.names.includes(route.name) || this.paths.includes(route.path); 10 | }, 11 | }; 12 | 13 | function resetRoutes(router, store) { 14 | const options = baseOptions; 15 | if(!!router){ 16 | const oldRoutes = router.getRoutes(); 17 | oldRoutes.forEach((oldRoute) => { 18 | router.removeRoute(oldRoute.name); 19 | }); 20 | options.routes.forEach((newRoute) => { 21 | router.addRoute(newRoute); 22 | }); 23 | } 24 | return options; 25 | } 26 | 27 | async function initRouter({ store }) { 28 | const options = resetRoutes(null, store); 29 | // options.history = createWebHistory(process.env.VUE_APP_PUBLIC_PATH); 30 | options.history = createWebHashHistory(); 31 | return createRouter(options); 32 | } 33 | 34 | export { loginIgnore, initRouter, resetRoutes }; 35 | -------------------------------------------------------------------------------- /gui/apps/ztm/llm/router/main.js: -------------------------------------------------------------------------------- 1 | const main = { 2 | path: "main", 3 | name: "Main", 4 | redirect: "/main", 5 | children: [ 6 | { 7 | path: '/main', 8 | name: 'tunnels', 9 | component: () => import('../views/Main.vue') 10 | }, 11 | ], 12 | }; 13 | 14 | export default main; 15 | -------------------------------------------------------------------------------- /gui/apps/ztm/llm/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "vuex"; 2 | import modules from "./modules"; 3 | 4 | const store = createStore({ modules }); 5 | 6 | export default store; 7 | -------------------------------------------------------------------------------- /gui/apps/ztm/llm/store/modules/app.js: -------------------------------------------------------------------------------- 1 | export default { 2 | namespaced: true, 3 | state: { 4 | info:null, 5 | }, 6 | getters: { 7 | info: (state) => { 8 | return state.info; 9 | }, 10 | }, 11 | mutations: { 12 | setInfo(state, info) { 13 | state.info = info; 14 | }, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /gui/apps/ztm/llm/store/modules/index.js: -------------------------------------------------------------------------------- 1 | import app from "./app"; 2 | import notice from "@/store/modules/notice"; 3 | 4 | export default { app, notice }; 5 | -------------------------------------------------------------------------------- /gui/apps/ztm/llm/views/Main.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 20 | 21 | -------------------------------------------------------------------------------- /gui/apps/ztm/llm/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url'; 2 | import { defineConfig, loadEnv } from 'vite'; 3 | import vue from '@vitejs/plugin-vue'; 4 | import { resolve } from 'path'; 5 | import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'; 6 | export default defineConfig(async (config) => { 7 | return { 8 | base:"./", 9 | clearScreen: false, 10 | optimizeDeps: { 11 | dynamicImportVars: true, 12 | }, 13 | server: { 14 | port: 1426, 15 | strictPort: true, 16 | proxy: { 17 | '/api': { 18 | target: `http://0.0.0.0:${loadEnv(config.mode, process.cwd()).VITE_APP_API_PORT}/`, 19 | changeOrigin: true, 20 | }, 21 | } 22 | }, 23 | plugins: [ 24 | vue({reactivityTransform: true}), 25 | createSvgIconsPlugin({ 26 | iconDirs: [resolve(process.cwd(), '../../../src/assets/svg')], 27 | symbolId: 'svg-[name]', // 自定义 symbolId 模板 28 | }), 29 | ], 30 | resolve: { 31 | alias: { 32 | '@': fileURLToPath(new URL('../../../src', import.meta.url)) 33 | } 34 | } 35 | } 36 | }); 37 | -------------------------------------------------------------------------------- /gui/apps/ztm/proxy/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 21 | 22 | -------------------------------------------------------------------------------- /gui/apps/ztm/proxy/bootstrap.js: -------------------------------------------------------------------------------- 1 | import { loadInterceptors } from "@/service/common/request"; 2 | import interceptors from "@/service/common/axios-interceptors"; 3 | import guards from "./router/guards"; 4 | 5 | let appOptions = { 6 | router: undefined, 7 | store: undefined, 8 | }; 9 | 10 | function loadGuards(guards, options) { 11 | const { beforeEach, afterEach } = guards; 12 | const { router } = options; 13 | beforeEach.forEach((guard) => { 14 | if (guard && typeof guard === "function") { 15 | router.beforeEach((to, from, next) => guard(to, from, next, options)); 16 | } 17 | }); 18 | afterEach.forEach((guard) => { 19 | if (guard && typeof guard === "function") { 20 | router.afterEach((to, from) => guard(to, from, options)); 21 | } 22 | }); 23 | } 24 | 25 | function setAppOptions(options) { 26 | const { router, store } = options; 27 | appOptions.router = router; 28 | appOptions.store = store; 29 | } 30 | 31 | function bootstrap({ router, store }) { 32 | setAppOptions({ router, store }); 33 | loadInterceptors(interceptors, { router, store }); 34 | loadGuards(guards, { router, store }); 35 | } 36 | 37 | export default bootstrap; 38 | -------------------------------------------------------------------------------- /gui/apps/ztm/proxy/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Proxy - ZTM 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /gui/apps/ztm/proxy/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | import { initRouter } from "./router"; 4 | import store from "./store"; 5 | import PrimeVue from 'primevue/config'; 6 | import ToastService from 'primevue/toastservice'; 7 | import DialogService from 'primevue/dialogservice'; 8 | import ConfirmationService from 'primevue/confirmationservice'; 9 | import { useComponent } from '@/components'; 10 | import { useDirective } from '@/directives'; 11 | import rulesReg from '@/rules/reg'; 12 | import bootstrap from "./bootstrap"; 13 | import MyPreset from '@/theme'; 14 | import '@/assets/styles.scss'; 15 | import i18n from '@/i18n'; 16 | 17 | const app = createApp(App); 18 | app.use(PrimeVue, { 19 | ripple: true , 20 | theme: { 21 | preset: MyPreset, 22 | options: { 23 | prefix: 'p', 24 | darkModeSelector: 'system', 25 | cssLayer: false 26 | } 27 | } 28 | }); 29 | 30 | app.mixin({ 31 | mounted() { 32 | document.querySelectorAll('button:not(.link)').forEach(button => { 33 | button.addEventListener('click', event => { 34 | event.preventDefault(); 35 | }); 36 | }); 37 | } 38 | }); 39 | 40 | useComponent(app); 41 | useDirective(app); 42 | app.use(store); 43 | app.use(ToastService); 44 | app.use(DialogService); 45 | app.use(ConfirmationService); 46 | app.use(i18n); 47 | 48 | async function setRouter() { 49 | const router = await initRouter({ store }); 50 | app.use(router); 51 | app.mount("#app"); 52 | bootstrap({ router, store }); 53 | } 54 | setRouter(); -------------------------------------------------------------------------------- /gui/apps/ztm/proxy/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/apps/ztm/proxy/public/favicon.ico -------------------------------------------------------------------------------- /gui/apps/ztm/proxy/router/config.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | import main from "./main"; 3 | import EmptyLayout from '@/layout/EmptyLayout.vue'; 4 | 5 | const options = { 6 | routes: [ 7 | { 8 | path: "/:pathMatch(.*)", 9 | name: "404", 10 | component: () => import('@/views/pages/NotFound.vue') 11 | }, 12 | { 13 | path: "/403", 14 | name: "403", 15 | component: () => import('@/views/pages/auth/Access.vue') 16 | }, 17 | { 18 | path: '/error', 19 | name: 'error', 20 | component: () => import('@/views/pages/auth/Error.vue') 21 | }, 22 | { 23 | path: '/', 24 | component: EmptyLayout, 25 | redirect: "/main", 26 | children: [ 27 | main 28 | ] 29 | }, 30 | ], 31 | }; 32 | 33 | options.initRoutes = _.cloneDeep(options.routes); 34 | export default options; 35 | -------------------------------------------------------------------------------- /gui/apps/ztm/proxy/router/guards.js: -------------------------------------------------------------------------------- 1 | import ProxyService from '../service/ProxyService'; 2 | import NProgress from "nprogress"; 3 | import "nprogress/nprogress.css"; 4 | import { useToast } from "primevue/usetoast"; 5 | import { useStore } from 'vuex'; 6 | NProgress.configure({ showSpinner: true }); 7 | 8 | const proxyService = new ProxyService(); 9 | 10 | 11 | /** 12 | * Progress Start 13 | * @param to 14 | * @param form 15 | * @param next 16 | */ 17 | const progressStart = (to, from, next) => { 18 | // start progress bar 19 | if (!NProgress.isStarted()) { 20 | NProgress.start(); 21 | } 22 | next(); 23 | }; 24 | 25 | /** 26 | * App Info Guard 27 | * @param to 28 | * @param form 29 | * @param next 30 | * @param options 31 | */ 32 | const infoGuard = (to, from, next, options) => { 33 | const { toast } = options; 34 | const store = useStore(); 35 | const _info = store.getters['app/info'] 36 | if(!!_info){ 37 | next(); 38 | } else { 39 | proxyService.getInfo() 40 | .then(res => { 41 | store.commit('app/setInfo', res); 42 | next(); 43 | }) 44 | .catch(err => { 45 | console.log('Request Failed', err); 46 | }); 47 | } 48 | }; 49 | 50 | /** 51 | * Progress Done 52 | * @param to 53 | * @param form 54 | * @param options 55 | */ 56 | const progressDone = () => { 57 | // finish progress bar 58 | NProgress.done(); 59 | }; 60 | 61 | export default { 62 | beforeEach: [ 63 | progressStart, 64 | infoGuard, 65 | ], 66 | afterEach: [progressDone], 67 | }; 68 | -------------------------------------------------------------------------------- /gui/apps/ztm/proxy/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory } from 'vue-router'; 2 | import { isAdmin } from "@/service/common/authority-utils"; 3 | import baseOptions from './config'; 4 | 5 | const loginIgnore = { 6 | names: ["404", "403", "Login", "Root"], 7 | paths: ["/login","/root"], 8 | includes(route) { 9 | return this.names.includes(route.name) || this.paths.includes(route.path); 10 | }, 11 | }; 12 | 13 | function resetRoutes(router, store) { 14 | const options = baseOptions; 15 | if(!!router){ 16 | const oldRoutes = router.getRoutes(); 17 | oldRoutes.forEach((oldRoute) => { 18 | router.removeRoute(oldRoute.name); 19 | }); 20 | options.routes.forEach((newRoute) => { 21 | router.addRoute(newRoute); 22 | }); 23 | } 24 | return options; 25 | } 26 | 27 | async function initRouter({ store }) { 28 | const options = resetRoutes(null, store); 29 | // options.history = createWebHistory(process.env.VUE_APP_PUBLIC_PATH); 30 | options.history = createWebHashHistory(); 31 | return createRouter(options); 32 | } 33 | 34 | export { loginIgnore, initRouter, resetRoutes }; 35 | -------------------------------------------------------------------------------- /gui/apps/ztm/proxy/router/main.js: -------------------------------------------------------------------------------- 1 | const main = { 2 | path: "main", 3 | name: "Main", 4 | redirect: "/main", 5 | children: [ 6 | { 7 | path: '/main', 8 | name: 'tunnels', 9 | component: () => import('../views/Main.vue') 10 | }, 11 | ], 12 | }; 13 | 14 | export default main; 15 | -------------------------------------------------------------------------------- /gui/apps/ztm/proxy/service/ProxyService.js: -------------------------------------------------------------------------------- 1 | import { request, merge, spread } from '@/service/common/request'; 2 | import toast from "@/utils/toast"; 3 | import confirm from "@/utils/confirm"; 4 | import ZtmService from '@/service/ZtmService'; 5 | const ztmService = new ZtmService(); 6 | export default class ProxyService { 7 | getInfo() { 8 | return request(`/api/appinfo`); 9 | } 10 | getGroups() { 11 | const _mesh = ztmService.getAppMesh() 12 | return request(`/api/meshes/${_mesh}/apps/ztm/users/api/groups`); 13 | } 14 | getUsers() { 15 | return request(`/api/users`); 16 | } 17 | getEndpoints(mesh,params) { 18 | return ztmService.getEndpoints(mesh,params); 19 | } 20 | getProxy(ep) { 21 | return request(`/api/endpoints/${ep}/config`) 22 | } 23 | setProxy({ep, listen, targets, exclusions, rules}) { 24 | const body = {}; 25 | if(!!rules && rules.length>0){ 26 | body.rules = rules 27 | } 28 | if(!!listen){ 29 | body.listen = listen 30 | } 31 | const _targets = !!targets?targets.filter((t)=>!!t):[]; 32 | if(_targets.length > 0){ 33 | body.targets = _targets 34 | } 35 | const _exclusions = !!exclusions?exclusions.filter((t)=>!!t):[]; 36 | if(_exclusions.length > 0){ 37 | body.exclusions = _exclusions 38 | } 39 | return request(`/api/endpoints/${ep}/config`,"POST", body) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /gui/apps/ztm/proxy/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "vuex"; 2 | import modules from "./modules"; 3 | 4 | const store = createStore({ modules }); 5 | 6 | export default store; 7 | -------------------------------------------------------------------------------- /gui/apps/ztm/proxy/store/modules/app.js: -------------------------------------------------------------------------------- 1 | export default { 2 | namespaced: true, 3 | state: { 4 | info:null, 5 | }, 6 | getters: { 7 | info: (state) => { 8 | return state.info; 9 | }, 10 | }, 11 | mutations: { 12 | setInfo(state, info) { 13 | state.info = info; 14 | }, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /gui/apps/ztm/proxy/store/modules/index.js: -------------------------------------------------------------------------------- 1 | import app from "./app"; 2 | import notice from "@/store/modules/notice"; 3 | 4 | export default { app, notice }; 5 | -------------------------------------------------------------------------------- /gui/apps/ztm/proxy/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url'; 2 | import { defineConfig, loadEnv } from 'vite'; 3 | import vue from '@vitejs/plugin-vue'; 4 | import { resolve } from 'path'; 5 | import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'; 6 | export default defineConfig(async (config) => { 7 | return { 8 | base:"./", 9 | clearScreen: false, 10 | optimizeDeps: { 11 | dynamicImportVars: true, 12 | }, 13 | server: { 14 | port: 1424, 15 | strictPort: true, 16 | proxy: { 17 | '/api': { 18 | target: `http://0.0.0.0:${loadEnv(config.mode, process.cwd()).VITE_APP_API_PORT}/`, 19 | changeOrigin: true, 20 | }, 21 | } 22 | }, 23 | plugins: [ 24 | vue({reactivityTransform: true}), 25 | createSvgIconsPlugin({ 26 | iconDirs: [resolve(process.cwd(), '../../../src/assets/svg')], 27 | symbolId: 'svg-[name]', // 自定义 symbolId 模板 28 | }), 29 | ], 30 | resolve: { 31 | alias: { 32 | '@': fileURLToPath(new URL('../../../src', import.meta.url)) 33 | } 34 | } 35 | } 36 | }); 37 | -------------------------------------------------------------------------------- /gui/apps/ztm/script/.gitignore: -------------------------------------------------------------------------------- 1 | /public/scriptList.json -------------------------------------------------------------------------------- /gui/apps/ztm/script/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 21 | 22 | -------------------------------------------------------------------------------- /gui/apps/ztm/script/bootstrap.js: -------------------------------------------------------------------------------- 1 | import { loadInterceptors } from "@/service/common/request"; 2 | import interceptors from "@/service/common/axios-interceptors"; 3 | import guards from "./router/guards"; 4 | 5 | let appOptions = { 6 | router: undefined, 7 | store: undefined, 8 | }; 9 | 10 | function loadGuards(guards, options) { 11 | const { beforeEach, afterEach } = guards; 12 | const { router } = options; 13 | beforeEach.forEach((guard) => { 14 | if (guard && typeof guard === "function") { 15 | router.beforeEach((to, from, next) => guard(to, from, next, options)); 16 | } 17 | }); 18 | afterEach.forEach((guard) => { 19 | if (guard && typeof guard === "function") { 20 | router.afterEach((to, from) => guard(to, from, options)); 21 | } 22 | }); 23 | } 24 | 25 | function setAppOptions(options) { 26 | const { router, store } = options; 27 | appOptions.router = router; 28 | appOptions.store = store; 29 | } 30 | 31 | function bootstrap({ router, store }) { 32 | setAppOptions({ router, store }); 33 | loadInterceptors(interceptors, { router, store }); 34 | loadGuards(guards, { router, store }); 35 | } 36 | 37 | export default bootstrap; 38 | -------------------------------------------------------------------------------- /gui/apps/ztm/script/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Script - ZTM 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /gui/apps/ztm/script/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | import { initRouter } from "./router"; 4 | import store from "./store"; 5 | import PrimeVue from 'primevue/config'; 6 | import ToastService from 'primevue/toastservice'; 7 | import DialogService from 'primevue/dialogservice'; 8 | import ConfirmationService from 'primevue/confirmationservice'; 9 | import { useComponent } from '@/components'; 10 | import { useDirective } from '@/directives'; 11 | import rulesReg from '@/rules/reg'; 12 | import bootstrap from "./bootstrap"; 13 | import MyPreset from '@/theme'; 14 | import '@/assets/styles.scss'; 15 | import i18n from '@/i18n'; 16 | 17 | const app = createApp(App); 18 | app.use(PrimeVue, { 19 | ripple: true , 20 | theme: { 21 | preset: MyPreset, 22 | options: { 23 | prefix: 'p', 24 | darkModeSelector: 'system', 25 | cssLayer: false 26 | } 27 | } 28 | }); 29 | 30 | app.mixin({ 31 | mounted() { 32 | document.querySelectorAll('button:not(.link)').forEach(button => { 33 | button.addEventListener('click', event => { 34 | event.preventDefault(); 35 | }); 36 | }); 37 | } 38 | }); 39 | 40 | useComponent(app); 41 | useDirective(app); 42 | app.use(store); 43 | app.use(ToastService); 44 | app.use(DialogService); 45 | app.use(ConfirmationService); 46 | app.use(i18n); 47 | 48 | async function setRouter() { 49 | const router = await initRouter({ store }); 50 | app.use(router); 51 | app.mount("#app"); 52 | bootstrap({ router, store }); 53 | } 54 | setRouter(); -------------------------------------------------------------------------------- /gui/apps/ztm/script/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/apps/ztm/script/public/favicon.ico -------------------------------------------------------------------------------- /gui/apps/ztm/script/public/scriptList.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "http.js", 4 | "ping.js", 5 | "scan.js" 6 | ] 7 | } -------------------------------------------------------------------------------- /gui/apps/ztm/script/router/config.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | import main from "./main"; 3 | import EmptyLayout from '@/layout/EmptyLayout.vue'; 4 | 5 | const options = { 6 | routes: [ 7 | { 8 | path: "/:pathMatch(.*)", 9 | name: "404", 10 | component: () => import('@/views/pages/NotFound.vue') 11 | }, 12 | { 13 | path: "/403", 14 | name: "403", 15 | component: () => import('@/views/pages/auth/Access.vue') 16 | }, 17 | { 18 | path: '/error', 19 | name: 'error', 20 | component: () => import('@/views/pages/auth/Error.vue') 21 | }, 22 | { 23 | path: '/', 24 | component: EmptyLayout, 25 | redirect: "/main", 26 | children: [ 27 | main 28 | ] 29 | }, 30 | ], 31 | }; 32 | 33 | options.initRoutes = _.cloneDeep(options.routes); 34 | export default options; 35 | -------------------------------------------------------------------------------- /gui/apps/ztm/script/router/guards.js: -------------------------------------------------------------------------------- 1 | import ScriptService from '../service/ScriptService'; 2 | import NProgress from "nprogress"; 3 | import "nprogress/nprogress.css"; 4 | import { useToast } from "primevue/usetoast"; 5 | import { useStore } from 'vuex'; 6 | NProgress.configure({ showSpinner: true }); 7 | 8 | const scriptService = new ScriptService(); 9 | 10 | 11 | /** 12 | * Progress Start 13 | * @param to 14 | * @param form 15 | * @param next 16 | */ 17 | const progressStart = (to, from, next) => { 18 | // start progress bar 19 | if (!NProgress.isStarted()) { 20 | NProgress.start(); 21 | } 22 | next(); 23 | }; 24 | 25 | /** 26 | * App Info Guard 27 | * @param to 28 | * @param form 29 | * @param next 30 | * @param options 31 | */ 32 | const infoGuard = (to, from, next, options) => { 33 | const { toast } = options; 34 | const store = useStore(); 35 | const _info = store.getters['app/info'] 36 | if(!!_info){ 37 | next(); 38 | } else { 39 | scriptService.getInfo() 40 | .then(res => { 41 | next(); 42 | store.commit('app/setInfo', res); 43 | }) 44 | .catch(err => console.log('Request Failed', err)); 45 | } 46 | }; 47 | 48 | /** 49 | * Progress Done 50 | * @param to 51 | * @param form 52 | * @param options 53 | */ 54 | const progressDone = () => { 55 | // finish progress bar 56 | NProgress.done(); 57 | }; 58 | 59 | export default { 60 | beforeEach: [ 61 | progressStart, 62 | infoGuard, 63 | ], 64 | afterEach: [progressDone], 65 | }; 66 | -------------------------------------------------------------------------------- /gui/apps/ztm/script/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory } from 'vue-router'; 2 | import { isAdmin } from "@/service/common/authority-utils"; 3 | import baseOptions from './config'; 4 | 5 | const loginIgnore = { 6 | names: ["404", "403", "Login", "Root"], 7 | paths: ["/login","/root"], 8 | includes(route) { 9 | return this.names.includes(route.name) || this.paths.includes(route.path); 10 | }, 11 | }; 12 | 13 | function resetRoutes(router, store) { 14 | const options = baseOptions; 15 | if(!!router){ 16 | const oldRoutes = router.getRoutes(); 17 | oldRoutes.forEach((oldRoute) => { 18 | router.removeRoute(oldRoute.name); 19 | }); 20 | options.routes.forEach((newRoute) => { 21 | router.addRoute(newRoute); 22 | }); 23 | } 24 | return options; 25 | } 26 | 27 | async function initRouter({ store }) { 28 | const options = resetRoutes(null, store); 29 | // options.history = createWebHistory(process.env.VUE_APP_PUBLIC_PATH); 30 | options.history = createWebHashHistory(); 31 | return createRouter(options); 32 | } 33 | 34 | export { loginIgnore, initRouter, resetRoutes }; 35 | -------------------------------------------------------------------------------- /gui/apps/ztm/script/router/main.js: -------------------------------------------------------------------------------- 1 | const main = { 2 | path: "main", 3 | name: "Main", 4 | redirect: "/main", 5 | children: [ 6 | { 7 | path: '/main', 8 | name: 'scripts', 9 | component: () => import('../views/Main.vue') 10 | }, 11 | ], 12 | }; 13 | 14 | export default main; 15 | -------------------------------------------------------------------------------- /gui/apps/ztm/script/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "vuex"; 2 | import modules from "./modules"; 3 | 4 | const store = createStore({ modules }); 5 | 6 | export default store; 7 | -------------------------------------------------------------------------------- /gui/apps/ztm/script/store/modules/app.js: -------------------------------------------------------------------------------- 1 | export default { 2 | namespaced: true, 3 | state: { 4 | info:null, 5 | }, 6 | getters: { 7 | info: (state) => { 8 | return state.info; 9 | }, 10 | }, 11 | mutations: { 12 | setInfo(state, info) { 13 | state.info = info; 14 | }, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /gui/apps/ztm/script/store/modules/index.js: -------------------------------------------------------------------------------- 1 | import app from "./app"; 2 | import notice from "@/store/modules/notice"; 3 | 4 | export default { app, notice }; 5 | -------------------------------------------------------------------------------- /gui/apps/ztm/script/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url'; 2 | import { defineConfig, loadEnv } from 'vite'; 3 | import vue from '@vitejs/plugin-vue'; 4 | // import monacoEditorPlugin from 'vite-plugin-monaco-editor'; 5 | import { resolve, join } from 'path'; 6 | import fs from 'fs'; 7 | import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'; 8 | 9 | // 用于生成脚本列表的函数 10 | async function generateScriptList() { 11 | const scriptsDir = join(__dirname, 'public/scripts'); 12 | const files = await fs.promises.readdir(scriptsDir); 13 | const scriptFiles = files.filter(file => file.endsWith('.js')); 14 | 15 | const outputPath = join(__dirname, 'public/scriptList.json'); 16 | await fs.promises.writeFile(outputPath, JSON.stringify({ files: scriptFiles }, null, 2)); 17 | } 18 | export default defineConfig(async (config) => { 19 | return { 20 | base:"./", 21 | clearScreen: false, 22 | optimizeDeps: { 23 | dynamicImportVars: true, 24 | }, 25 | server: { 26 | port: 1423, 27 | strictPort: true, 28 | proxy: { 29 | '/api': { 30 | target: `http://0.0.0.0:${loadEnv(config.mode, process.cwd()).VITE_APP_API_PORT}/`, 31 | changeOrigin: true, 32 | }, 33 | } 34 | }, 35 | plugins: [ 36 | generateScriptList(), 37 | vue({reactivityTransform: true}), 38 | createSvgIconsPlugin({ 39 | iconDirs: [resolve(process.cwd(), '../../../src/assets/svg')], 40 | symbolId: 'svg-[name]', // 自定义 symbolId 模板 41 | }), 42 | ], 43 | resolve: { 44 | alias: { 45 | '@': fileURLToPath(new URL('../../../src', import.meta.url)) 46 | } 47 | } 48 | } 49 | }); 50 | -------------------------------------------------------------------------------- /gui/apps/ztm/tunnel/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 21 | 22 | -------------------------------------------------------------------------------- /gui/apps/ztm/tunnel/bootstrap.js: -------------------------------------------------------------------------------- 1 | import { loadInterceptors } from "@/service/common/request"; 2 | import interceptors from "@/service/common/axios-interceptors"; 3 | import guards from "./router/guards"; 4 | 5 | let appOptions = { 6 | router: undefined, 7 | store: undefined, 8 | }; 9 | 10 | function loadGuards(guards, options) { 11 | const { beforeEach, afterEach } = guards; 12 | const { router } = options; 13 | beforeEach.forEach((guard) => { 14 | if (guard && typeof guard === "function") { 15 | router.beforeEach((to, from, next) => guard(to, from, next, options)); 16 | } 17 | }); 18 | afterEach.forEach((guard) => { 19 | if (guard && typeof guard === "function") { 20 | router.afterEach((to, from) => guard(to, from, options)); 21 | } 22 | }); 23 | } 24 | 25 | function setAppOptions(options) { 26 | const { router, store } = options; 27 | appOptions.router = router; 28 | appOptions.store = store; 29 | } 30 | 31 | function bootstrap({ router, store }) { 32 | setAppOptions({ router, store }); 33 | loadInterceptors(interceptors, { router, store }); 34 | loadGuards(guards, { router, store }); 35 | } 36 | 37 | export default bootstrap; 38 | -------------------------------------------------------------------------------- /gui/apps/ztm/tunnel/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tunnel - ZTM 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /gui/apps/ztm/tunnel/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | import { initRouter } from "./router"; 4 | import store from "./store"; 5 | import PrimeVue from 'primevue/config'; 6 | import ToastService from 'primevue/toastservice'; 7 | import DialogService from 'primevue/dialogservice'; 8 | import ConfirmationService from 'primevue/confirmationservice'; 9 | import { useComponent } from '@/components'; 10 | import { useDirective } from '@/directives'; 11 | import rulesReg from '@/rules/reg'; 12 | import bootstrap from "./bootstrap"; 13 | import MyPreset from '@/theme'; 14 | import '@/assets/styles.scss'; 15 | import i18n from '@/i18n'; 16 | 17 | const app = createApp(App); 18 | app.use(PrimeVue, { 19 | ripple: true , 20 | theme: { 21 | preset: MyPreset, 22 | options: { 23 | prefix: 'p', 24 | darkModeSelector: 'system', 25 | cssLayer: false 26 | } 27 | } 28 | }); 29 | 30 | app.mixin({ 31 | mounted() { 32 | document.querySelectorAll('button:not(.link)').forEach(button => { 33 | button.addEventListener('click', event => { 34 | event.preventDefault(); 35 | }); 36 | }); 37 | } 38 | }); 39 | 40 | useComponent(app); 41 | useDirective(app); 42 | app.use(store); 43 | app.use(ToastService); 44 | app.use(DialogService); 45 | app.use(ConfirmationService); 46 | app.use(i18n); 47 | 48 | async function setRouter() { 49 | const router = await initRouter({ store }); 50 | app.use(router); 51 | app.mount("#app"); 52 | bootstrap({ router, store }); 53 | } 54 | setRouter(); -------------------------------------------------------------------------------- /gui/apps/ztm/tunnel/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/apps/ztm/tunnel/public/favicon.ico -------------------------------------------------------------------------------- /gui/apps/ztm/tunnel/router/config.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | import main from "./main"; 3 | import EmptyLayout from '@/layout/EmptyLayout.vue'; 4 | 5 | const options = { 6 | routes: [ 7 | { 8 | path: "/:pathMatch(.*)", 9 | name: "404", 10 | component: () => import('@/views/pages/NotFound.vue') 11 | }, 12 | { 13 | path: "/403", 14 | name: "403", 15 | component: () => import('@/views/pages/auth/Access.vue') 16 | }, 17 | { 18 | path: '/error', 19 | name: 'error', 20 | component: () => import('@/views/pages/auth/Error.vue') 21 | }, 22 | { 23 | path: '/', 24 | component: EmptyLayout, 25 | redirect: "/main", 26 | children: [ 27 | main 28 | ] 29 | }, 30 | ], 31 | }; 32 | 33 | options.initRoutes = _.cloneDeep(options.routes); 34 | export default options; 35 | -------------------------------------------------------------------------------- /gui/apps/ztm/tunnel/router/guards.js: -------------------------------------------------------------------------------- 1 | import TunnelService from '../service/TunnelService'; 2 | import NProgress from "nprogress"; 3 | import "nprogress/nprogress.css"; 4 | import { useToast } from "primevue/usetoast"; 5 | import { useStore } from 'vuex'; 6 | NProgress.configure({ showSpinner: true }); 7 | 8 | const tunnelService = new TunnelService(); 9 | 10 | 11 | /** 12 | * Progress Start 13 | * @param to 14 | * @param form 15 | * @param next 16 | */ 17 | const progressStart = (to, from, next) => { 18 | // start progress bar 19 | if (!NProgress.isStarted()) { 20 | NProgress.start(); 21 | } 22 | next(); 23 | }; 24 | 25 | /** 26 | * App Info Guard 27 | * @param to 28 | * @param form 29 | * @param next 30 | * @param options 31 | */ 32 | const infoGuard = (to, from, next, options) => { 33 | const { toast } = options; 34 | const store = useStore(); 35 | const _info = store.getters['app/info'] 36 | if(!!_info){ 37 | next(); 38 | } else { 39 | tunnelService.getInfo() 40 | .then(res => { 41 | next(); 42 | store.commit('app/setInfo', res); 43 | }) 44 | .catch(err => console.log('Request Failed', err)); 45 | } 46 | }; 47 | 48 | /** 49 | * Progress Done 50 | * @param to 51 | * @param form 52 | * @param options 53 | */ 54 | const progressDone = () => { 55 | // finish progress bar 56 | NProgress.done(); 57 | }; 58 | 59 | export default { 60 | beforeEach: [ 61 | progressStart, 62 | infoGuard, 63 | ], 64 | afterEach: [progressDone], 65 | }; 66 | -------------------------------------------------------------------------------- /gui/apps/ztm/tunnel/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory } from 'vue-router'; 2 | import { isAdmin } from "@/service/common/authority-utils"; 3 | import baseOptions from './config'; 4 | 5 | const loginIgnore = { 6 | names: ["404", "403", "Login", "Root"], 7 | paths: ["/login","/root"], 8 | includes(route) { 9 | return this.names.includes(route.name) || this.paths.includes(route.path); 10 | }, 11 | }; 12 | 13 | function resetRoutes(router, store) { 14 | const options = baseOptions; 15 | if(!!router){ 16 | const oldRoutes = router.getRoutes(); 17 | oldRoutes.forEach((oldRoute) => { 18 | router.removeRoute(oldRoute.name); 19 | }); 20 | options.routes.forEach((newRoute) => { 21 | router.addRoute(newRoute); 22 | }); 23 | } 24 | return options; 25 | } 26 | 27 | async function initRouter({ store }) { 28 | const options = resetRoutes(null, store); 29 | // options.history = createWebHistory(process.env.VUE_APP_PUBLIC_PATH); 30 | options.history = createWebHashHistory(); 31 | return createRouter(options); 32 | } 33 | 34 | export { loginIgnore, initRouter, resetRoutes }; 35 | -------------------------------------------------------------------------------- /gui/apps/ztm/tunnel/router/main.js: -------------------------------------------------------------------------------- 1 | const main = { 2 | path: "main", 3 | name: "Main", 4 | redirect: "/main", 5 | children: [ 6 | { 7 | path: '/main', 8 | name: 'tunnels', 9 | component: () => import('../views/Main.vue') 10 | }, 11 | ], 12 | }; 13 | 14 | export default main; 15 | -------------------------------------------------------------------------------- /gui/apps/ztm/tunnel/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "vuex"; 2 | import modules from "./modules"; 3 | 4 | const store = createStore({ modules }); 5 | 6 | export default store; 7 | -------------------------------------------------------------------------------- /gui/apps/ztm/tunnel/store/modules/app.js: -------------------------------------------------------------------------------- 1 | export default { 2 | namespaced: true, 3 | state: { 4 | info:null, 5 | }, 6 | getters: { 7 | info: (state) => { 8 | return state.info; 9 | }, 10 | }, 11 | mutations: { 12 | setInfo(state, info) { 13 | state.info = info; 14 | }, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /gui/apps/ztm/tunnel/store/modules/index.js: -------------------------------------------------------------------------------- 1 | import app from "./app"; 2 | import notice from "@/store/modules/notice"; 3 | 4 | export default { app, notice }; 5 | -------------------------------------------------------------------------------- /gui/apps/ztm/tunnel/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url'; 2 | import { defineConfig, loadEnv } from 'vite'; 3 | import vue from '@vitejs/plugin-vue'; 4 | import { resolve } from 'path'; 5 | import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'; 6 | export default defineConfig(async (config) => { 7 | return { 8 | base:"./", 9 | clearScreen: false, 10 | optimizeDeps: { 11 | dynamicImportVars: true, 12 | }, 13 | server: { 14 | port: 1422, 15 | strictPort: true, 16 | proxy: { 17 | '/api': { 18 | target: `http://0.0.0.0:${loadEnv(config.mode, process.cwd()).VITE_APP_API_PORT}/`, 19 | changeOrigin: true, 20 | }, 21 | } 22 | }, 23 | plugins: [ 24 | vue({reactivityTransform: true}), 25 | createSvgIconsPlugin({ 26 | iconDirs: [resolve(process.cwd(), '../../../src/assets/svg')], 27 | symbolId: 'svg-[name]', // 自定义 symbolId 模板 28 | }), 29 | ], 30 | resolve: { 31 | alias: { 32 | '@': fileURLToPath(new URL('../../../src', import.meta.url)) 33 | } 34 | } 35 | } 36 | }); 37 | -------------------------------------------------------------------------------- /gui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ZTM 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /gui/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/public/favicon.ico -------------------------------------------------------------------------------- /gui/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/src-android/.gitignore: -------------------------------------------------------------------------------- 1 | ztm.keystore 2 | keystore.base64 3 | /app/src/main/assets/libc++_shared.so 4 | /app/src/main/assets/libztm.so -------------------------------------------------------------------------------- /gui/src-android/app/src/main/assets/copy.md: -------------------------------------------------------------------------------- 1 | CopyBinaryActivity.kt will move libztm.so & libc++_shared.so to android private folder -------------------------------------------------------------------------------- /gui/src-android/app/src/main/java/com/flomesh/ztm/BootReceiver.kt: -------------------------------------------------------------------------------- 1 | package com.flomesh.ztm 2 | 3 | import android.content.BroadcastReceiver 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.widget.Toast 7 | import android.os.Build 8 | 9 | class BootReceiver : BroadcastReceiver() { 10 | override fun onReceive(context: Context?, intent: Intent?) { 11 | if (intent?.action == Intent.ACTION_BOOT_COMPLETED) { 12 | Toast.makeText(context, "Device Boot Completed", Toast.LENGTH_SHORT).show() 13 | val serviceIntent = Intent(context, FloatingWindowService::class.java) 14 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 15 | context?.startForegroundService(serviceIntent) 16 | } else { 17 | context?.startService(serviceIntent) 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/drawable/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/drawable/close.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/drawable/gradient_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/drawable/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/drawable/ic_launcher.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/drawable/loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/drawable/loading.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/drawable/white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/drawable/white.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/layout/layout_floating_window.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 24 | 25 | -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/xml/file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /gui/src-android/app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 127.0.0.1 5 | 6 | 7 | -------------------------------------------------------------------------------- /gui/src-ios/.gitignore: -------------------------------------------------------------------------------- 1 | /apple/assets 2 | /apple/Externals -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /gui/src-ios/apple/ExportOptions.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | method 6 | debugging 7 | 8 | 9 | -------------------------------------------------------------------------------- /gui/src-ios/apple/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/Logo.png -------------------------------------------------------------------------------- /gui/src-ios/apple/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | 3 | target 'ztm_iOS' do 4 | platform :ios, '16.2' 5 | # Pods for ztm_iOS 6 | end 7 | 8 | target 'ztm_macOS' do 9 | platform :osx, '11.0' 10 | # Pods for ztm_macOS 11 | end 12 | 13 | # Delete the deployment target for iOS and macOS, causing it to be inherited from the Podfile 14 | post_install do |installer| 15 | installer.pods_project.targets.each do |target| 16 | target.build_configurations.each do |config| 17 | config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' 18 | config.build_settings.delete 'MACOSX_DEPLOYMENT_TARGET' 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /gui/src-ios/apple/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryFileTimestamp 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | C617.1 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /gui/src-ios/apple/RunnerWidget/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /gui/src-ios/apple/RunnerWidget/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /gui/src-ios/apple/RunnerWidget/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /gui/src-ios/apple/RunnerWidget/Assets.xcassets/ShareAppIcon.imageset/AppIcon-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/RunnerWidget/Assets.xcassets/ShareAppIcon.imageset/AppIcon-20x20@1x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/RunnerWidget/Assets.xcassets/ShareAppIcon.imageset/AppIcon-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/RunnerWidget/Assets.xcassets/ShareAppIcon.imageset/AppIcon-20x20@2x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/RunnerWidget/Assets.xcassets/ShareAppIcon.imageset/AppIcon-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/RunnerWidget/Assets.xcassets/ShareAppIcon.imageset/AppIcon-20x20@3x.png -------------------------------------------------------------------------------- /gui/src-ios/apple/RunnerWidget/Assets.xcassets/ShareAppIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "AppIcon-20x20@1x.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "AppIcon-20x20@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "AppIcon-20x20@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /gui/src-ios/apple/RunnerWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /gui/src-ios/apple/RunnerWidget/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.widgetkit-extension 9 | NSExtensionAttributes 10 | 11 | WKWidgetPreferredContentSizeCategory 12 | systemSmall 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /gui/src-ios/apple/RunnerWidget/RunnerWidgetBundle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RunnerWidgetBundle.swift 3 | // RunnerWidget 4 | // 5 | // Created by 林东臣 on 2024/9/14. 6 | // 7 | 8 | import WidgetKit 9 | import SwiftUI 10 | 11 | 12 | @main 13 | struct RunnerWidgetBundle: WidgetBundle { 14 | var body: some Widget { 15 | RunnerWidget() 16 | RunnerWidgetLiveActivity() 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gui/src-ios/apple/RunnerWidgetExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | com.apple.security.application-groups 8 | 9 | group.com.flomesh.ztm 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /gui/src-ios/apple/ShareExtension/Base.lproj/MainInterface.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /gui/src-ios/apple/ShareExtension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionAttributes 8 | 9 | NSExtensionActivationRule 10 | 11 | NSExtensionActivationSupportsFileWithMaxCount 12 | 1 13 | NSExtensionActivationSupportsImageWithMaxCount 14 | 1 15 | NSExtensionActivationSupportsMovieWithMaxCount 16 | 1 17 | NSExtensionActivationSupportsText 18 | 19 | NSExtensionActivationSupportsWebPageWithMaxCount 20 | 1 21 | NSExtensionActivationSupportsWebURLWithMaxCount 22 | 1 23 | NSExtensionActivationUsesStrictMatching 24 | 25 | 26 | NSExtensionActivationSupportsFileWithContentUTI 27 | 28 | public.data 29 | 30 | NSExtensionItemThumbnailImageName 31 | paperplane 32 | 33 | NSExtensionMainStoryboard 34 | MainInterface 35 | NSExtensionPointIdentifier 36 | com.apple.share-services 37 | 38 | NSExtensionDisplayName 39 | Share To ZTM 40 | NSPhotoLibraryUsageDescription 41 | NSPhotoLibraryUsageDescription 42 | NSFileAccessUsageDescription 43 | NSFileAccessUsageDescription 44 | 45 | 46 | -------------------------------------------------------------------------------- /gui/src-ios/apple/ShareExtension/ShareExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.icloud-container-identifiers 6 | 7 | iCloud.com.flomesh.ztm 8 | 9 | com.apple.developer.icloud-services 10 | 11 | CloudDocuments 12 | 13 | com.apple.developer.ubiquity-container-identifiers 14 | 15 | iCloud.com.flomesh.ztm 16 | 17 | com.apple.security.application-groups 18 | 19 | group.com.flomesh.ztm 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /gui/src-ios/apple/Sources/ztm/LocationManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocationManager.swift 3 | // ztm_iOS 4 | // 5 | // Created by 林东臣 on 2024/9/16. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | import CoreLocation 11 | 12 | class LocationManager: NSObject { 13 | private let locationManager = CLLocationManager() 14 | 15 | override init() { 16 | super.init() 17 | 18 | // 请求始终允许访问位置信息的权限 19 | locationManager.requestWhenInUseAuthorization() 20 | locationManager.requestAlwaysAuthorization() 21 | 22 | // 启用后台定位模式 23 | locationManager.allowsBackgroundLocationUpdates = true 24 | 25 | // 当位置权限被禁止时,不会请求权限 26 | locationManager.pausesLocationUpdatesAutomatically = false 27 | 28 | // locationManager.delegate = self 29 | } 30 | 31 | func startLocationUpdates() { 32 | // 开始接收位置更新 33 | locationManager.startUpdatingLocation() 34 | } 35 | 36 | // CLLocationManagerDelegate 方法 37 | func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { 38 | // 当位置更新时调用 39 | if let location = locations.last { 40 | NSLog("定位更新: \(location.coordinate.latitude), \(location.coordinate.longitude)") 41 | } 42 | } 43 | 44 | func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { 45 | NSLog("定位失败: \(error.localizedDescription)") 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /gui/src-ios/apple/Sources/ztm/bindings/bindings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace ffi { 4 | extern "C" { 5 | void start_app(); 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /gui/src-ios/apple/Sources/ztm/main.mm: -------------------------------------------------------------------------------- 1 | #include 2 | #import 3 | #include "bindings/bindings.h" 4 | #include 5 | #import "ztm-Swift.h" 6 | 7 | 8 | int main(int argc, char * argv[]) { 9 | @autoreleasepool { 10 | [ActivityHelper watchEvent]; 11 | [ActivityHelper startLiveActivity]; 12 | ffi::start_app(); 13 | return 0; 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /gui/src-ios/apple/Sources/ztm/ztm_iOS-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // ztm_iOS-Bridging-Header.h 3 | // ztm_iOS 4 | // 5 | // Created by 林东臣 on 2024/9/14. 6 | // 7 | 8 | #ifndef ztm_iOS_Bridging_Header_h 9 | #define ztm_iOS_Bridging_Header_h 10 | 11 | #endif /* ztm_iOS_Bridging_Header_h */ 12 | -------------------------------------------------------------------------------- /gui/src-ios/apple/ztm.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /gui/src-ios/apple/ztm.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /gui/src-ios/apple/ztm.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Original 7 | DisableBuildSystemDeprecationDiagnostic 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /gui/src-ios/apple/ztm.xcodeproj/project.xcworkspace/xcuserdata/lindongchen.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-ios/apple/ztm.xcodeproj/project.xcworkspace/xcuserdata/lindongchen.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /gui/src-ios/apple/ztm.xcodeproj/xcuserdata/lindongchen.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ProxyWidget.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 2 11 | 12 | RunnerWidgetExtension.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 1 16 | 17 | ShareExtension.xcscheme_^#shared#^_ 18 | 19 | orderHint 20 | 2 21 | 22 | ztm_iOS.xcscheme_^#shared#^_ 23 | 24 | orderHint 25 | 0 26 | 27 | 28 | SuppressBuildableAutocreation 29 | 30 | 676495AA2CDF8EF8005BA6DB 31 | 32 | primary 33 | 34 | 35 | 67E60F272C98280A002E4B6B 36 | 37 | primary 38 | 39 | 40 | 7E6F12527796DEEAB78B87F8 41 | 42 | primary 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /gui/src-ios/apple/ztm_iOS/ztm_iOS.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | com.apple.developer.icloud-container-identifiers 8 | 9 | iCloud.com.flomesh.ztm 10 | 11 | com.apple.developer.icloud-services 12 | 13 | CloudDocuments 14 | 15 | com.apple.developer.ubiquity-container-identifiers 16 | 17 | iCloud.com.flomesh.ztm 18 | 19 | com.apple.security.app-sandbox 20 | 21 | com.apple.security.application-groups 22 | 23 | group.com.flomesh.ztm 24 | 25 | keychain-access-groups 26 | 27 | $(AppIdentifierPrefix)com.flomesh.ztm 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /gui/src-ios/bak/ProxyWidget/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionAttributes 8 | 9 | NEProviderProtocols 10 | 11 | New item 12 | 13 | NEVPNProtocol 14 | NEAppProxyProvider 15 | 16 | NSExtensionPointIdentifier 17 | com.apple.networkextension.app-proxy 18 | NSExtensionPrincipalClass 19 | $(PRODUCT_MODULE_NAME).AppProxyProvider 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /gui/src-ios/bak/ProxyWidget/ProxyWidget.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.networking.networkextension 6 | 7 | app-proxy-provider 8 | content-filter-provider 9 | packet-tunnel-provider 10 | 11 | com.apple.developer.networking.vpn.api 12 | 13 | allow-vpn 14 | 15 | com.apple.security.application-groups 16 | 17 | group.com.flomesh.ztm 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /gui/src-ios/setup_lib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 检查参数是否正确传入 4 | if [ "$#" -ne 2 ]; then 5 | echo "Usage: $0 " 6 | exit 1 7 | fi 8 | 9 | 10 | # 变量定义 11 | PROJECT_DIR=$1 12 | SOURCE_DYLIB_PATH=$2 13 | DYLIB_NAME=$(basename "$SOURCE_DYLIB_PATH") 14 | XCODE_PROJECT_PATH="$PROJECT_DIR/Runner.xcodeproj" 15 | 16 | # 将动态库复制到 Xcode 的 Frameworks 目录 17 | cp "$SOURCE_DYLIB_PATH" "$PROJECT_DIR/" 18 | 19 | # 配置 Xcode 项目 20 | cd "$PROJECT_DIR" 21 | 22 | # 添加 Run Script Phase 来确保动态库在构建时被复制 23 | RUN_SCRIPT_PHASE="cp -R \"$PROJECT_DIR/$DYLIB_NAME\" \"\$TARGET_BUILD_DIR/\$FRAMEWORKS_FOLDER_PATH/\"" 24 | 25 | # 使用 xcodeproj 命令行工具添加 Run Script Phase 26 | /usr/libexec/PlistBuddy -c "Add :targets:0:buildPhases:0:runScripts:0 script string \"$RUN_SCRIPT_PHASE\"" "$XCODE_PROJECT_PATH/project.pbxproj" 27 | 28 | # 添加到 Link Binary With Libraries 29 | /usr/libexec/PlistBuddy -c "Add :targets:0:buildPhases:0:files:0:buildFile fileRef string \"$DYLIB_NAME\"" "$XCODE_PROJECT_PATH/project.pbxproj" 30 | 31 | echo "Xcode 项目配置完成" 32 | -------------------------------------------------------------------------------- /gui/src-plugin/.gitignore: -------------------------------------------------------------------------------- 1 | tauri-plugin-share 2 | tauri-plugin-keychain -------------------------------------------------------------------------------- /gui/src-tauri/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Generated by Tauri 6 | # will have schema files for capabilities auto-completion 7 | /gen 8 | /.cargo 9 | Cargo.lock -------------------------------------------------------------------------------- /gui/src-tauri/Entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.allow-unsigned-executable-memory 6 | 7 | com.apple.security.device.microphone 8 | 9 | com.apple.security.device.audio-input 10 | 11 | com.apple.security.device.camera 12 | 13 | 14 | -------------------------------------------------------------------------------- /gui/src-tauri/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSCameraUsageDescription 6 | ZTM Requires camera access in order to capture and transmit video 7 | NSMicrophoneUsageDescription 8 | ZTM Requires microphone access in order to capture and transmit audio 9 | 10 | -------------------------------------------------------------------------------- /gui/src-tauri/bin/.gitignore: -------------------------------------------------------------------------------- 1 | # macOS aarch64 2 | ztmctl-aarch64-apple-darwin 3 | 4 | # macOS x86 5 | ztmctl-x86_64-apple-darwin 6 | 7 | # Windows 8 | ztmctl-x86_64-pc-windows-msvc.exe 9 | 10 | # Linux 11 | ztmctl-x86_64-unknown-linux-gnu 12 | 13 | # Android 14 | ztmctl-aarch64-linux-android 15 | ztmctl-armv7-linux-androideabi 16 | 17 | # IOS 18 | ztmctl-aarch64-apple-ios-sim 19 | libpipy.dylib -------------------------------------------------------------------------------- /gui/src-tauri/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | tauri_build::build() 3 | } 4 | -------------------------------------------------------------------------------- /gui/src-tauri/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/128x128.png -------------------------------------------------------------------------------- /gui/src-tauri/icons/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/128x128@2x.png -------------------------------------------------------------------------------- /gui/src-tauri/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/32x32.png -------------------------------------------------------------------------------- /gui/src-tauri/icons/Square107x107Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/Square107x107Logo.png -------------------------------------------------------------------------------- /gui/src-tauri/icons/Square142x142Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/Square142x142Logo.png -------------------------------------------------------------------------------- /gui/src-tauri/icons/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/Square150x150Logo.png -------------------------------------------------------------------------------- /gui/src-tauri/icons/Square284x284Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/Square284x284Logo.png -------------------------------------------------------------------------------- /gui/src-tauri/icons/Square30x30Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/Square30x30Logo.png -------------------------------------------------------------------------------- /gui/src-tauri/icons/Square310x310Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/Square310x310Logo.png -------------------------------------------------------------------------------- /gui/src-tauri/icons/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/Square44x44Logo.png -------------------------------------------------------------------------------- /gui/src-tauri/icons/Square71x71Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/Square71x71Logo.png -------------------------------------------------------------------------------- /gui/src-tauri/icons/Square89x89Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/Square89x89Logo.png -------------------------------------------------------------------------------- /gui/src-tauri/icons/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/StoreLogo.png -------------------------------------------------------------------------------- /gui/src-tauri/icons/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/background.png -------------------------------------------------------------------------------- /gui/src-tauri/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/icon.icns -------------------------------------------------------------------------------- /gui/src-tauri/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/icon.ico -------------------------------------------------------------------------------- /gui/src-tauri/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/icon.png -------------------------------------------------------------------------------- /gui/src-tauri/icons/icon2.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src-tauri/icons/icon2.icns -------------------------------------------------------------------------------- /gui/src-tauri/scripts/proxy-win.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | if "%~1"=="" ( 5 | exit /b 1 6 | ) 7 | 8 | set Action=%~1 9 | set Proxy=%~2 10 | set RegPath="HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" 11 | 12 | if "%Action%"=="register" ( 13 | if "%Proxy%"=="" ( 14 | echo Proxy address is required for registration. 15 | exit /b 1 16 | ) 17 | reg add %RegPath% /v ProxyEnable /t REG_DWORD /d 1 /f >nul 2>&1 18 | reg add %RegPath% /v ProxyServer /t REG_SZ /d "%Proxy%" /f >nul 2>&1 19 | exit /b 0 20 | ) 21 | 22 | if "%Action%"=="unregister" ( 23 | reg add %RegPath% /v ProxyEnable /t REG_DWORD /d 0 /f >nul 2>&1 24 | reg delete %RegPath% /v ProxyServer /f >nul 2>&1 25 | exit /b 0 26 | ) 27 | 28 | exit /b 1 29 | 30 | -------------------------------------------------------------------------------- /gui/src-tauri/scripts/proxy-win2.ps1: -------------------------------------------------------------------------------- 1 | param ( 2 | [string]$Action, 3 | [string]$Proxy 4 | ) 5 | 6 | function Set-Proxy { 7 | if (-not $Proxy) { exit 1 } 8 | try { 9 | $regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" 10 | Set-ItemProperty -Path $regPath -Name ProxyEnable -Value 1 11 | Set-ItemProperty -Path $regPath -Name ProxyServer -Value $Proxy 12 | exit 0 13 | } catch { exit 1 } 14 | } 15 | 16 | function Unset-Proxy { 17 | try { 18 | $regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" 19 | Set-ItemProperty -Path $regPath -Name ProxyEnable -Value 0 20 | Remove-ItemProperty -Path $regPath -Name ProxyServer -ErrorAction SilentlyContinue 21 | exit 0 22 | } catch { exit 1 } 23 | } 24 | 25 | switch ($Action) { 26 | "register" { Set-Proxy } 27 | "unregister" { Unset-Proxy } 28 | default { exit 1 } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /gui/src-tauri/src/bak.rs: -------------------------------------------------------------------------------- 1 | 2 | // #[command] 3 | // fn shareFile(app: tauri::AppHandle, url: String, mimeType: String) -> Result { 4 | // let handle = thread::spawn(move || -> Result<(), String> { 5 | // #[cfg(target_os = "ios")] 6 | // unsafe { 7 | // warn!("share in"); 8 | // let cls = Class::get("ShareHandler").expect("ShareHandler class not found"); 9 | // let shared_manager: *mut Object = msg_send![cls, sharedManager]; 10 | 11 | // let ns_url_class = Class::get("NSURL").expect("NSURL class not found"); 12 | // let ns_url: *mut Object = msg_send![ns_url_class, URLWithString: NSString::from_str(&url)]; 13 | // let _: () = msg_send![shared_manager, shareFile: ns_url]; 14 | 15 | // warn!("share end"); 16 | // } 17 | // Ok(()) 18 | // }); 19 | // let thread_id_str = format!("{:?}", handle.thread().id()); 20 | // Ok(thread_id_str) 21 | // } -------------------------------------------------------------------------------- /gui/src-tauri/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 2 | use fix_path_env::fix; 3 | 4 | fn main() { 5 | if let Err(e) = fix() { 6 | println!("{}", e); 7 | } else { 8 | println!("PATH: {}", std::env::var("PATH").unwrap()); 9 | } 10 | ztm_lib::run(); 11 | } 12 | -------------------------------------------------------------------------------- /gui/src-tauri/tauri.android.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "bundle": { 3 | "active": true, 4 | "targets": "all", 5 | "resources": [], 6 | "externalBin": [], 7 | "icon": [ 8 | "icons/32x32.png", 9 | "icons/128x128.png", 10 | "icons/128x128@2x.png", 11 | "icons/icon.icns", 12 | "icons/icon.ico" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /gui/src-tauri/tauri.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "productName": "ztm", 3 | "version": "1.0.0", 4 | "identifier": "com.flomesh.ztm", 5 | "build": { 6 | "beforeDevCommand": "npm run dev", 7 | "devUrl": "http://localhost:1420", 8 | "beforeBuildCommand": "", 9 | "frontendDist": "../../agent/gui" 10 | }, 11 | "app": { 12 | "windows": [ 13 | { 14 | "dragDropEnabled": false, 15 | "title": "ZTM", 16 | "width": 455, 17 | "height": 350, 18 | "resizable": false, 19 | "fullscreen": false, 20 | "visible": true 21 | } 22 | ], 23 | "security": { 24 | "csp": null, 25 | "dangerousDisableAssetCspModification": false, 26 | "freezePrototype": false, 27 | "assetProtocol": { 28 | "enable": true, 29 | "scope": { 30 | "allow": ["$APPDATA/**", "$HOME/**", "$RESOURCE/**", "$DOCUMENT/**"] 31 | } 32 | }, 33 | "capabilities": ["main-capability"] 34 | }, 35 | "withGlobalTauri": true, 36 | "macOSPrivateApi": true 37 | }, 38 | "bundle": { 39 | "active": true, 40 | "targets": ["deb", "rpm"], 41 | "resources": ["scripts/proxy-linux.sh"], 42 | "externalBin": ["bin/ztmctl"], 43 | "icon": [ 44 | "icons/32x32.png", 45 | "icons/128x128.png", 46 | "icons/128x128@2x.png", 47 | "icons/icon.icns", 48 | "icons/icon.ico" 49 | ] 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /gui/src-tauri/tauri.ios.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "bundle": { 3 | "active": true, 4 | "targets": "all", 5 | "resources": [], 6 | "iOS": { 7 | "minimumSystemVersion": "16.2" 8 | }, 9 | "externalBin": [], 10 | "icon": [ 11 | "icons/32x32.png", 12 | "icons/128x128.png", 13 | "icons/128x128@2x.png", 14 | "icons/icon.icns", 15 | "icons/icon.ico" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /gui/src-tauri/tauri.macos.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "bundle": { 3 | "active": true, 4 | "targets": "all", 5 | "resources": ["scripts/proxy-mac.sh"], 6 | "externalBin": ["bin/ztmctl"], 7 | "icon": [ 8 | "icons/32x32.png", 9 | "icons/128x128.png", 10 | "icons/128x128@2x.png", 11 | "icons/icon.icns", 12 | "icons/icon.ico" 13 | ], 14 | "macOS": { 15 | "entitlements": "./Entitlements.plist" 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /gui/src-tauri/tauri.windows.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "windows": [ 4 | { 5 | "dragDropEnabled": false, 6 | "title": "ZTM", 7 | "width": 455, 8 | "height": 350, 9 | "resizable": false, 10 | "fullscreen": false, 11 | "visible": true 12 | } 13 | ], 14 | "security": { 15 | "assetProtocol": { 16 | "enable": false, 17 | "scope": [] 18 | }, 19 | "dangerousDisableAssetCspModification": false, 20 | "freezePrototype": false, 21 | "capabilities": ["windows-capability"] 22 | }, 23 | "withGlobalTauri": true 24 | }, 25 | "bundle": { 26 | "active": true, 27 | "targets": "all", 28 | "resources": ["scripts/proxy-win.cmd"], 29 | "externalBin": ["bin/ztmctl"], 30 | "icon": [ 31 | "icons/32x32.png", 32 | "icons/128x128.png", 33 | "icons/128x128@2x.png", 34 | "icons/icon.icns", 35 | "icons/icon.ico" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /gui/src/assets/img/apps/appstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/appstore.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/browser.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/chat.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/cloud.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/console.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/default.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/ep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/ep.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/ep2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/ep2.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/eplog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/eplog.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/llm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/llm.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/mesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/mesh.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/proxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/proxy.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/rdp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/rdp.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/script.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/script.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/script2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/script2.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/setting.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/shortcut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/shortcut.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/terminal.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/tunnel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/tunnel.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/users.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/users.png -------------------------------------------------------------------------------- /gui/src/assets/img/apps/ztmlog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/apps/ztmlog.png -------------------------------------------------------------------------------- /gui/src/assets/img/bot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/bot.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/excel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/excel.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/file.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/folder.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/img.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/img2.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/mirror.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/mirror.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/mp3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/mp3.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/mp4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/mp4.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/pdf.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/ppt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/ppt.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/share.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/txt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/txt.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/userfolder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/userfolder.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/word.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/zip.png -------------------------------------------------------------------------------- /gui/src/assets/img/files/zip2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/files/zip2.png -------------------------------------------------------------------------------- /gui/src/assets/img/gpt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/gpt.png -------------------------------------------------------------------------------- /gui/src/assets/img/hover-web-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/hover-web-logo.png -------------------------------------------------------------------------------- /gui/src/assets/img/llm/deepseek.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/llm/deepseek.png -------------------------------------------------------------------------------- /gui/src/assets/img/loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/loading.png -------------------------------------------------------------------------------- /gui/src/assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/logo.png -------------------------------------------------------------------------------- /gui/src/assets/img/mcp/excel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/mcp/excel.png -------------------------------------------------------------------------------- /gui/src/assets/img/mcp/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/mcp/github.png -------------------------------------------------------------------------------- /gui/src/assets/img/mcp/mcp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/mcp/mcp.png -------------------------------------------------------------------------------- /gui/src/assets/img/mcp/mcp2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/mcp/mcp2.png -------------------------------------------------------------------------------- /gui/src/assets/img/pipy-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/pipy-white.png -------------------------------------------------------------------------------- /gui/src/assets/img/service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/service.png -------------------------------------------------------------------------------- /gui/src/assets/img/system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/system.png -------------------------------------------------------------------------------- /gui/src/assets/img/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/user.png -------------------------------------------------------------------------------- /gui/src/assets/img/vue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/src/assets/img/web-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/web-logo.png -------------------------------------------------------------------------------- /gui/src/assets/img/white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flomesh-io/ztm/aba0bc7694e9119820d62177ed870db792660375/gui/src/assets/img/white.png -------------------------------------------------------------------------------- /gui/src/assets/layout/_config.scss: -------------------------------------------------------------------------------- 1 | .layout-wrapper { 2 | 3 | 4 | .layout-config-sidebar { 5 | &.p-sidebar { 6 | .p-sidebar-content { 7 | padding-left: 2rem; 8 | padding-right: 2rem; 9 | } 10 | } 11 | } 12 | } 13 | .layout-config-button { 14 | display: block; 15 | position: fixed; 16 | width: 2.5rem; 17 | height: 2.5rem; 18 | line-height: 2.5rem; 19 | background: var(--p-primary-color); 20 | color: var(--p-primary-color-text); 21 | text-align: center; 22 | top: 50%; 23 | right: 0; 24 | margin-top: -1.5rem; 25 | border-top-left-radius: var(--p-border-radius); 26 | border-bottom-left-radius: var(--p-border-radius); 27 | border-top-right-radius: 0; 28 | border-bottom-right-radius: 0; 29 | transition: background-color var(--p-transition-duration); 30 | overflow: hidden; 31 | cursor: pointer; 32 | z-index: 999; 33 | box-shadow: -0.25rem 0 1rem rgba(0, 0, 0, 0.15); 34 | 35 | i { 36 | font-size: 2rem; 37 | line-height: inherit; 38 | transform: rotate(0deg); 39 | transition: transform 1s; 40 | } 41 | .p-button-icon{ 42 | font-size: 1.6rem; 43 | line-height: inherit; 44 | transform: rotate(0deg); 45 | transition: transform 1s; 46 | } 47 | .p-button-icon:before{ 48 | position: relative; 49 | top: -0.6rem; 50 | left:0.2rem; 51 | } 52 | 53 | &:hover { 54 | background: var(--p-primary-400); 55 | } 56 | } -------------------------------------------------------------------------------- /gui/src/assets/layout/_content.scss: -------------------------------------------------------------------------------- 1 | .layout-main-container { 2 | display: flex; 3 | flex-direction: column; 4 | min-height: calc(100vh); 5 | justify-content: space-between; 6 | padding: 0; 7 | transition: margin-left $transitionDuration; 8 | flex: 1; 9 | overflow-x: hidden; 10 | } 11 | 12 | .layout-main { 13 | flex: 1 1 auto; 14 | display: flex;flex-direction: column; 15 | } -------------------------------------------------------------------------------- /gui/src/assets/layout/_footer.scss: -------------------------------------------------------------------------------- 1 | .layout-footer { 2 | transition: margin-left $transitionDuration; 3 | display: flex; 4 | align-items: center; 5 | justify-content: center; 6 | padding-top: 1rem; 7 | border-top: 1px solid var(--p-surface-border); 8 | } 9 | -------------------------------------------------------------------------------- /gui/src/assets/layout/_main.scss: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | html { 6 | height: 100%; 7 | font-size: $scale; 8 | background-color: var(--p-surface-html); 9 | } 10 | 11 | body { 12 | font-family: var(--p-font-family); 13 | color: var(--p-text-color); 14 | background-color: var(--p-surface-html); 15 | margin: 0; 16 | padding: 0; 17 | min-height: 100%; 18 | -webkit-font-smoothing: antialiased; 19 | -moz-osx-font-smoothing: grayscale; 20 | } 21 | a { 22 | text-decoration: none; 23 | } 24 | 25 | .layout-wrapper { 26 | position: relative; 27 | padding: env(safe-area-inset-top, 0) 0 0 0; 28 | min-height: calc(100vh - env(safe-area-inset-bottom, 0)); 29 | display: flex; 30 | flex-direction: row; 31 | } -------------------------------------------------------------------------------- /gui/src/assets/layout/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin focused() { 2 | outline: 0 none; 3 | outline-offset: 0; 4 | transition: box-shadow .2s; 5 | box-shadow: var(--p-focus-ring); 6 | } 7 | 8 | @mixin focused-inset() { 9 | outline: 0 none; 10 | outline-offset: 0; 11 | transition: box-shadow .2s; 12 | box-shadow: inset var(--p-focus-ring); 13 | } 14 | -------------------------------------------------------------------------------- /gui/src/assets/layout/_preloading.scss: -------------------------------------------------------------------------------- 1 | .preloader { 2 | position: fixed; 3 | z-index: 999999; 4 | background: #edf1f5; 5 | width: 100%; 6 | height: 100%; 7 | } 8 | .preloader-content { 9 | border: 0 solid transparent; 10 | border-radius: 50%; 11 | width: 150px; 12 | height: 150px; 13 | position: absolute; 14 | top: calc(50vh - 75px); 15 | left: calc(50vw - 75px); 16 | } 17 | 18 | .preloader-content:before, .preloader-content:after{ 19 | content: ''; 20 | border: 1em solid var(--p-primary-color); 21 | border-radius: 50%; 22 | width: inherit; 23 | height: inherit; 24 | position: absolute; 25 | top: 0; 26 | left: 0; 27 | animation: loader 2s linear infinite; 28 | opacity: 0; 29 | } 30 | 31 | .preloader-content:before{ 32 | animation-delay: 0.5s; 33 | } 34 | 35 | @keyframes loader{ 36 | 0%{ 37 | transform: scale(0); 38 | opacity: 0; 39 | } 40 | 50%{ 41 | opacity: 1; 42 | } 43 | 100%{ 44 | transform: scale(1); 45 | opacity: 0; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /gui/src/assets/layout/_typography.scss: -------------------------------------------------------------------------------- 1 | h1, h2, h3, h4, h5, h6 { 2 | margin: 1.5rem 0 1rem 0; 3 | font-family: inherit; 4 | font-weight: 500; 5 | line-height: 1.2; 6 | color: var(--p-surface-900); 7 | 8 | &:first-child { 9 | margin-top: 0; 10 | } 11 | } 12 | 13 | h1 { 14 | font-size: 2.5rem; 15 | } 16 | 17 | h2 { 18 | font-size: 2rem; 19 | } 20 | 21 | h3 { 22 | font-size: 1.75rem; 23 | } 24 | 25 | h4 { 26 | font-size: 1.5rem; 27 | } 28 | 29 | h5 { 30 | font-size: 1.25rem; 31 | } 32 | 33 | h6 { 34 | font-size: 1rem; 35 | } 36 | 37 | mark { 38 | background: #FFF8E1; 39 | padding: .25rem .4rem; 40 | border-radius: $borderRadius; 41 | font-family: monospace; 42 | } 43 | 44 | blockquote { 45 | margin: 1rem 0; 46 | padding: 0 2rem; 47 | border-left: 4px solid #90A4AE; 48 | } 49 | 50 | hr { 51 | border-top: solid var(--p-surface-border); 52 | border-width: 1px 0 0 0; 53 | margin: 1rem 0; 54 | } 55 | 56 | p { 57 | margin: 0 0 1rem 0; 58 | line-height: 1.5; 59 | 60 | &:last-child { 61 | margin-bottom: 0; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /gui/src/assets/layout/_utils.scss: -------------------------------------------------------------------------------- 1 | /* Utils */ 2 | .clearfix:after { 3 | content: " "; 4 | display: block; 5 | clear: both; 6 | } 7 | 8 | .card { 9 | background: var(--p-surface-card); 10 | border: 1px solid var(--p-surface-border); 11 | padding: 2rem; 12 | margin-bottom: 2rem; 13 | box-shadow: var(--p-card-shadow); 14 | border-radius: $borderRadius; 15 | 16 | &:last-child { 17 | margin-bottom: 0; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gui/src/assets/layout/_variables.scss: -------------------------------------------------------------------------------- 1 | /* General */ 2 | $scale:14px; /* main font size */ 3 | $borderRadius:12px; /* border radius of layout element e.g. card, sidebar */ 4 | $transitionDuration:.2s; /* transition duration of layout elements e.g. sidebar, overlay menus */ 5 | -------------------------------------------------------------------------------- /gui/src/assets/layout/layout.scss: -------------------------------------------------------------------------------- 1 | @import './_variables'; 2 | @import "./_mixins"; 3 | @import "./_preloading"; 4 | @import "./_main"; 5 | @import "./_topbar"; 6 | @import "./_menu"; 7 | @import "./_config"; 8 | @import "./_content"; 9 | @import "./_footer"; 10 | @import "./_responsive"; 11 | @import "./_utils"; 12 | @import "./_typography"; -------------------------------------------------------------------------------- /gui/src/assets/svg.css: -------------------------------------------------------------------------------- 1 | @keyframes linearAnimation { 2 | 0% { 3 | stroke-dasharray: 60; 4 | stroke-dashoffset: 60; 5 | } 6 | 100% { 7 | stroke-dasharray: 60; 8 | stroke-dashoffset: 0; 9 | } 10 | } 11 | svg { 12 | /* width: 200px; */ 13 | /* height: 200px; */ 14 | } 15 | 16 | .svg{ 17 | width:20px; 18 | height: 20px; 19 | color: var(--p-text-color); 20 | } 21 | .svg.linear{ 22 | animation: linearAnimation 3s linear 1; 23 | } -------------------------------------------------------------------------------- /gui/src/assets/svg/apps.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/src/assets/svg/back.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/src/assets/svg/chat.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/src/assets/svg/cloud.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/src/assets/svg/endpoint.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/src/assets/svg/grid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/src/assets/svg/home.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/src/assets/svg/log.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/src/assets/svg/mesh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/src/assets/svg/network.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/src/assets/vue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/src/bootstrap.js: -------------------------------------------------------------------------------- 1 | import { loadInterceptors } from "@/service/common/request"; 2 | import interceptors from "@/service/common/axios-interceptors"; 3 | import guards from "@/router/guards"; 4 | 5 | let appOptions = { 6 | router: undefined, 7 | store: undefined, 8 | }; 9 | 10 | function loadGuards(guards, options) { 11 | const { beforeEach, afterEach } = guards; 12 | const { router } = options; 13 | beforeEach.forEach((guard) => { 14 | if (guard && typeof guard === "function") { 15 | router.beforeEach((to, from, next) => guard(to, from, next, options)); 16 | } 17 | }); 18 | afterEach.forEach((guard) => { 19 | if (guard && typeof guard === "function") { 20 | router.afterEach((to, from) => guard(to, from, options)); 21 | } 22 | }); 23 | } 24 | 25 | function setAppOptions(options) { 26 | const { router, store } = options; 27 | appOptions.router = router; 28 | appOptions.store = store; 29 | } 30 | 31 | function bootstrap({ router, store }) { 32 | setAppOptions({ router, store }); 33 | loadInterceptors(interceptors, { router, store }); 34 | loadGuards(guards, { router, store }); 35 | } 36 | 37 | export default bootstrap; 38 | -------------------------------------------------------------------------------- /gui/src/components/Loading.vue: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /gui/src/components/common/Avatar.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 53 | 54 | -------------------------------------------------------------------------------- /gui/src/components/common/BaseCard.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /gui/src/components/common/Card.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 42 | 43 | -------------------------------------------------------------------------------- /gui/src/components/common/DataViewLayoutOptions.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 35 | -------------------------------------------------------------------------------- /gui/src/components/common/DrawMenu.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 39 | 40 | -------------------------------------------------------------------------------- /gui/src/components/common/Ep.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 31 | 32 | -------------------------------------------------------------------------------- /gui/src/components/common/FloatField.vue: -------------------------------------------------------------------------------- 1 | 9 | 18 | -------------------------------------------------------------------------------- /gui/src/components/common/FormItem.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /gui/src/components/common/HiddenField.vue: -------------------------------------------------------------------------------- 1 | 9 | 15 | -------------------------------------------------------------------------------- /gui/src/components/editor/JsEditor.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 63 | -------------------------------------------------------------------------------- /gui/src/components/editor/ShellEditor.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 75 | -------------------------------------------------------------------------------- /gui/src/directives.js: -------------------------------------------------------------------------------- 1 | import StyleClass from 'primevue/styleclass'; 2 | import Ripple from 'primevue/ripple'; 3 | import Tooltip from 'primevue/tooltip'; 4 | import BadgeDirective from 'primevue/badgedirective'; 5 | import longtap from './directives/longtap'; 6 | 7 | 8 | export function useDirective(app){ 9 | app.directive('tooltip', Tooltip); 10 | app.directive('badge', BadgeDirective); 11 | app.directive('ripple', Ripple); 12 | app.directive('styleclass', StyleClass); 13 | app.directive('longtap', longtap); 14 | } 15 | -------------------------------------------------------------------------------- /gui/src/directives/longtap.js: -------------------------------------------------------------------------------- 1 | export default { 2 | mounted(el, binding) { 3 | const duration = binding.arg || 600; 4 | let timer = null; 5 | 6 | const start = (event) => { 7 | if ((event.type === 'mousedown' || event.type === 'touchstart') && event?.button != 2) { 8 | timer = setTimeout(() => { 9 | event.preventDefault(); 10 | binding.value(event); 11 | }, duration); 12 | } 13 | }; 14 | 15 | const cancel = (event) => { 16 | if (timer) { 17 | clearTimeout(timer); 18 | timer = null; 19 | } 20 | }; 21 | 22 | const preventContextMenu = (event) => { 23 | event.preventDefault(); 24 | binding.value(event); 25 | }; 26 | 27 | el._start = start; 28 | el._cancel = cancel; 29 | el._preventContextMenu = preventContextMenu; 30 | 31 | el.addEventListener('mousedown', start); 32 | el.addEventListener('touchstart', start); 33 | el.addEventListener('mouseup', cancel); 34 | el.addEventListener('mouseout', cancel); 35 | el.addEventListener('touchend', cancel); 36 | el.addEventListener('touchcancel', cancel); 37 | el.addEventListener('contextmenu', preventContextMenu); 38 | }, 39 | 40 | unmounted(el) { 41 | el.removeEventListener('mousedown', el._start); 42 | el.removeEventListener('touchstart', el._start); 43 | el.removeEventListener('mouseup', el._cancel); 44 | el.removeEventListener('mouseout', el._cancel); 45 | el.removeEventListener('touchend', el._cancel); 46 | el.removeEventListener('touchcancel', el._cancel); 47 | 48 | delete el._start; 49 | delete el._cancel; 50 | } 51 | }; -------------------------------------------------------------------------------- /gui/src/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "hello": "Hello, World!" 3 | } -------------------------------------------------------------------------------- /gui/src/i18n/index.js: -------------------------------------------------------------------------------- 1 | import { createI18n } from 'vue-i18n'; 2 | 3 | // 导入语言文件 4 | import en from './en.json'; 5 | import zh from './zh.json'; 6 | 7 | const messages = { 8 | en, 9 | zh, 10 | }; 11 | const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; 12 | let tzLang = 'en'; 13 | if (timeZone === "Asia/Shanghai" || timeZone === "Asia/Chongqing") { 14 | tzLang = 'zh' 15 | } else if (timeZone === "Asia/Hong_Kong") { 16 | tzLang = 'zh' 17 | } 18 | const defaultLang = localStorage.getItem('lang')|| tzLang ||import.meta.env.VITE_APP_LANG; 19 | // 创建 i18n 实例 20 | const i18n = createI18n({ 21 | locale: defaultLang, 22 | fallbackLocale: 'en', 23 | messages, 24 | }); 25 | 26 | export default i18n; -------------------------------------------------------------------------------- /gui/src/layout/AppFooter.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 17 | -------------------------------------------------------------------------------- /gui/src/layout/AppMenu.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /gui/src/layout/AppSidebar.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /gui/src/layout/menu.js: -------------------------------------------------------------------------------- 1 | import { platform } from '@tauri-apps/plugin-os'; 2 | const menus = { 3 | tauri: [ 4 | { 5 | label: 'Meshes',short:'Mesh', svg: '#svg-mesh', route: '/mesh/list' 6 | }, 7 | { 8 | label: 'Endpoints',short:'EP', svg: '#svg-endpoint', route: '/mesh/endpoints' 9 | }, 10 | { 11 | label: 'Chat',short:'Chat', svg: '#svg-log', route: '/mesh/chat' 12 | }, 13 | { 14 | label: 'Cloud',short:'Cloud', svg: '#svg-cloud', app: '/api/meshes/Local/apps/ztm/cloud/' 15 | }, 16 | // { 17 | // label: 'Logs',short:'Log', svg: '#svg-log', route: '/mesh/log' 18 | // }, 19 | ], 20 | web: [ 21 | { 22 | label: 'Meshes',short:'Mesh', svg: '#svg-mesh', route: '/mesh/list' 23 | }, 24 | { 25 | label: 'Endpoints',short:'EP', svg: '#svg-endpoint', route: '/mesh/endpoints' 26 | }, 27 | { 28 | label: 'Chat',short:'Chat', svg: '#svg-chat', route: '/mesh/chat' 29 | }, 30 | { 31 | label: 'Cloud',short:'Cloud', svg: '#svg-cloud', app: '/api/meshes/Local/apps/ztm/cloud/' 32 | }, 33 | { 34 | label: 'Apps',short:'Apps', svg: '#svg-grid', route: '/mesh/apps' 35 | }, 36 | // { 37 | // label: 'Logs',short:'Log', svg: '#svg-log', route: '/mesh/log' 38 | // }, 39 | ], 40 | }; 41 | 42 | export function getMenu(){ 43 | return menus[!!window.__TAURI_INTERNALS__ && platform() != "android" && platform() != "ios" ?'tauri':'web']; 44 | } 45 | -------------------------------------------------------------------------------- /gui/src/main.js: -------------------------------------------------------------------------------- 1 | // import 'vite/modulepreload-polyfill' 2 | import { createApp } from 'vue'; 3 | import App from './App.vue'; 4 | import { initRouter } from "./router"; 5 | import store from "./store"; 6 | import PrimeVue from 'primevue/config'; 7 | import ToastService from 'primevue/toastservice'; 8 | import DialogService from 'primevue/dialogservice'; 9 | import ConfirmationService from 'primevue/confirmationservice'; 10 | import { useComponent } from './components'; 11 | import { useDirective } from './directives'; 12 | import rulesReg from './rules/reg'; 13 | import bootstrap from "@/bootstrap"; 14 | import MyPreset from './theme'; 15 | import '@/assets/styles.scss'; 16 | import 'virtual:svg-icons-register'; 17 | import i18n from './i18n'; 18 | 19 | const app = createApp(App); 20 | app.use(PrimeVue, { 21 | ripple: true , 22 | theme: { 23 | preset: MyPreset, 24 | options: { 25 | prefix: 'p', 26 | darkModeSelector: 'system', 27 | cssLayer: false 28 | } 29 | } 30 | }); 31 | 32 | app.mixin({ 33 | mounted() { 34 | document.querySelectorAll('button:not(.link)').forEach(button => { 35 | button.addEventListener('click', event => { 36 | event.preventDefault(); 37 | }); 38 | }); 39 | } 40 | }); 41 | 42 | useComponent(app); 43 | useDirective(app); 44 | app.use(store); 45 | app.use(ToastService); 46 | app.use(DialogService); 47 | app.use(ConfirmationService); 48 | app.use(i18n); 49 | 50 | async function setRouter() { 51 | const router = await initRouter({ store }); 52 | app.use(router); 53 | app.mount("#app"); 54 | bootstrap({ router, store }); 55 | } 56 | setRouter(); -------------------------------------------------------------------------------- /gui/src/router/config.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | import mesh from "./modules/mesh"; 3 | import app from "./modules/app"; 4 | import AppLayout from '@/layout/AppLayout.vue'; 5 | import { isPC } from '@/utils/platform'; 6 | 7 | const options = { 8 | routes: [ 9 | { 10 | path: "/login", 11 | name: "Login", 12 | component: () => import('@/views/pages/auth/Login.vue') 13 | }, 14 | { 15 | path: "/:pathMatch(.*)", 16 | name: "404", 17 | component: () => import('@/views/pages/NotFound.vue') 18 | }, 19 | { 20 | path: "/403", 21 | name: "403", 22 | component: () => import('@/views/pages/auth/Access.vue') 23 | }, 24 | { 25 | path: '/error', 26 | name: 'error', 27 | component: () => import('@/views/pages/auth/Error.vue') 28 | }, 29 | { 30 | path: '/root', 31 | name: 'Root', 32 | component: () => import('@/layout/AppRoot.vue') 33 | }, 34 | { 35 | ...app 36 | }, 37 | { 38 | path: '/', 39 | redirect: "/root", 40 | children: [ 41 | mesh 42 | ] 43 | }, 44 | ], 45 | }; 46 | 47 | if(!isPC()){ 48 | options.routes[options.routes.length -1].component = AppLayout; 49 | } 50 | options.initRoutes = _.cloneDeep(options.routes); 51 | export default options; 52 | -------------------------------------------------------------------------------- /gui/src/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory } from 'vue-router'; 2 | import { isAdmin } from "@/service/common/authority-utils"; 3 | import baseOptions from '@/router/config'; 4 | 5 | const loginIgnore = { 6 | names: ["404", "403", "Login", "Root"], 7 | paths: ["/login","/root"], 8 | includes(route) { 9 | return this.names.includes(route.name) || this.paths.includes(route.path); 10 | }, 11 | }; 12 | 13 | function resetRoutes(router, store) { 14 | const options = baseOptions; 15 | if(!!router){ 16 | const oldRoutes = router.getRoutes(); 17 | oldRoutes.forEach((oldRoute) => { 18 | router.removeRoute(oldRoute.name); 19 | }); 20 | options.routes.forEach((newRoute) => { 21 | router.addRoute(newRoute); 22 | }); 23 | } 24 | return options; 25 | } 26 | 27 | async function initRouter({ store }) { 28 | const options = resetRoutes(null, store); 29 | // options.history = createWebHistory(process.env.VUE_APP_PUBLIC_PATH); 30 | options.history = createWebHashHistory(); 31 | return createRouter(options); 32 | } 33 | 34 | export { loginIgnore, initRouter, resetRoutes }; 35 | -------------------------------------------------------------------------------- /gui/src/router/modules/app.js: -------------------------------------------------------------------------------- 1 | const app = { 2 | path: "/app", 3 | name: "Apps", 4 | children: [ 5 | { 6 | path: '/app/term', 7 | name: 'Rerm', 8 | component: () => import('@/views/apps/core/TermContent.vue') 9 | }, 10 | { 11 | path: '/app/rdp', 12 | name: 'RDP', 13 | component: () => import('@/views/apps/core/RDP.vue') 14 | }, 15 | { 16 | path: '/app/ztmlog', 17 | name: 'ZTM Log', 18 | component: () => import('@/views/apps/core/ZtmLog.vue') 19 | }, 20 | 21 | { 22 | path: '/app/log/:mesh/:ep/:provider/:app', 23 | name: 'app log', 24 | component: () => import('@/views/log/AppLog.vue') 25 | }, 26 | ], 27 | }; 28 | 29 | export default app; 30 | -------------------------------------------------------------------------------- /gui/src/router/modules/mesh.js: -------------------------------------------------------------------------------- 1 | const mesh = { 2 | path: "mesh", 3 | name: "Mesh", 4 | redirect: "/mesh/list", 5 | children: [ 6 | { 7 | path: '/mesh/list', 8 | name: 'meshes', 9 | component: () => import('@/views/mesh/Meshes.vue') 10 | }, 11 | { 12 | path: '/mesh/endpoints', 13 | name: 'endpoints', 14 | component: () => import('@/views/mesh/Endpoints.vue') 15 | }, 16 | { 17 | path: '/mesh/apps', 18 | name: 'apps', 19 | component: () => import('@/views/apps/AppStore.vue') 20 | }, 21 | { 22 | path: '/mesh/app/:provider/:name', 23 | name: 'app', 24 | component: () => import('@/views/apps/AppStore.vue') 25 | }, 26 | { 27 | path: '/mesh/log', 28 | name: 'ep log', 29 | component: () => import('@/views/log/EpLog.vue') 30 | }, 31 | { 32 | path: '/mesh/cloud', 33 | name: 'cloud', 34 | component: () => import('@/views/chat/Main.vue') 35 | }, 36 | { 37 | path: '/mesh/chat', 38 | name: 'chat', 39 | component: () => import('@/views/chat/Main.vue') 40 | }, 41 | ], 42 | }; 43 | 44 | export default mesh; 45 | -------------------------------------------------------------------------------- /gui/src/rules/index.js: -------------------------------------------------------------------------------- 1 | const rules = { 2 | name: { 3 | required: true, 4 | customAsync: true, 5 | // custom: (value) => { 6 | // if(false) { 7 | // return true; 8 | // } 9 | // return 'The text cannot be "test'; 10 | // }, 11 | }, 12 | uniqueName: (params) => { 13 | return { 14 | required: true, 15 | min:1, 16 | uniqueName: [params] 17 | } 18 | }, 19 | required: "required", 20 | } 21 | //required|min:6|custom:customRule 22 | export default rules; -------------------------------------------------------------------------------- /gui/src/service/common/axios-interceptors.js: -------------------------------------------------------------------------------- 1 | import Cookie from './cookie' 2 | 3 | const resp401 = { 4 | onFulfilled(response, options) { 5 | const { message } = options; 6 | if (response.code === 401) { 7 | message.error("No permission"); 8 | } 9 | return response; 10 | }, 11 | onRejected(error, options) { 12 | const { message } = options; 13 | const { response } = error; 14 | if (response.status === 401) { 15 | message.error("No permission"); 16 | } 17 | return Promise.reject(error); 18 | }, 19 | }; 20 | 21 | const resp403 = { 22 | onFulfilled(response, options) { 23 | const { message } = options; 24 | if (response.code === 403) { 25 | message.error("Request denied"); 26 | } 27 | return response; 28 | }, 29 | onRejected(error, options) { 30 | const { message } = options; 31 | const { response } = error; 32 | if (response.status === 403) { 33 | message.error("Request denied"); 34 | } 35 | return Promise.reject(error); 36 | }, 37 | }; 38 | 39 | const reqCommon = { 40 | onFulfilled(config) { 41 | const { url, xsrfCookieName } = config; 42 | if ( 43 | url.indexOf("login") === -1 && 44 | xsrfCookieName && 45 | !Cookie.get("Authorization") 46 | ) { 47 | // message.warning("The authentication token has expired. Please log in again"); 48 | } 49 | return config; 50 | }, 51 | onRejected(error, options) { 52 | const { message } = options; 53 | message.error(error.message); 54 | return Promise.reject(error); 55 | }, 56 | }; 57 | 58 | export default { 59 | request: [reqCommon], 60 | response: [resp401, resp403], 61 | }; 62 | -------------------------------------------------------------------------------- /gui/src/service/common/cookie.js: -------------------------------------------------------------------------------- 1 | import Cookie from "js-cookie"; 2 | const hasCookie = false; 3 | function set(key, value, option){ 4 | const _option = option || {}; 5 | if(hasCookie){ 6 | Cookie.set(key, value, { 7 | ..._option, 8 | }); 9 | } else { 10 | localStorage.setItem(key, value); 11 | } 12 | } 13 | function get(key){ 14 | if(hasCookie){ 15 | return Cookie.get(key); 16 | } else { 17 | return localStorage.getItem(key); 18 | } 19 | } 20 | function remove(key){ 21 | if(hasCookie){ 22 | Cookie.remove(key); 23 | } else { 24 | localStorage.removeItem(key); 25 | } 26 | } 27 | export default{ 28 | set, 29 | get, 30 | remove 31 | }; 32 | -------------------------------------------------------------------------------- /gui/src/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "vuex"; 2 | import modules from "./modules"; 3 | 4 | const store = createStore({ modules }); 5 | 6 | export default store; 7 | -------------------------------------------------------------------------------- /gui/src/store/modules/blob.js: -------------------------------------------------------------------------------- 1 | export default { 2 | namespaced: true, 3 | state: { 4 | urls:{}, 5 | }, 6 | getters: { 7 | urls: (state) => { 8 | return state.urls; 9 | }, 10 | }, 11 | mutations: { 12 | setUrl(state, n) { 13 | state.urls[n[0]] = n[1]; 14 | }, 15 | setUrls(state, urls) { 16 | state.urls = urls; 17 | }, 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /gui/src/store/modules/index.js: -------------------------------------------------------------------------------- 1 | import account from "./account"; 2 | import notice from "./notice"; 3 | import blob from "./blob"; 4 | import mcp from "./mcp"; 5 | 6 | export default { account, notice, blob, mcp }; 7 | -------------------------------------------------------------------------------- /gui/src/utils/clipboard.js: -------------------------------------------------------------------------------- 1 | import clipboard from 'clipboardy'; 2 | import toast from "@/utils/toast"; 3 | import { writeText, readText } from '@tauri-apps/plugin-clipboard-manager'; 4 | const copy = (text)=>{ 5 | if(!window.__TAURI_INTERNALS__ ){ 6 | clipboard.write(text).then(()=>{ 7 | toast.add({ severity: 'contrast', summary: 'Tips', detail: `Copied.`, life: 3000 }); 8 | }); 9 | } else { 10 | writeText(text).then(()=>{ 11 | toast.add({ severity: 'contrast', summary: 'Tips', detail: `Copied.`, life: 3000 }); 12 | }) 13 | } 14 | } 15 | 16 | export { 17 | copy 18 | }; -------------------------------------------------------------------------------- /gui/src/utils/confirm.js: -------------------------------------------------------------------------------- 1 | import store from '@/store'; 2 | 3 | const remove = (accept, cancel, msg) => { 4 | const confirm = store.getters["notice/confirm"]; 5 | confirm.require({ 6 | message: msg || `Are you sure you want to delete it?`, 7 | header: 'Tips', 8 | icon: 'pi pi-exclamation-triangle', 9 | rejectProps: { 10 | label: 'Cancel', 11 | severity: 'secondary', 12 | outlined: true 13 | }, 14 | acceptProps: { 15 | severity: 'danger', 16 | label: 'Delete' 17 | }, 18 | accept: () => { 19 | accept() 20 | }, 21 | reject: () => { 22 | !!cancel && cancel() 23 | } 24 | }) 25 | } 26 | const custom = ({ 27 | header,message,icon, accept, cancel 28 | }) => { 29 | const confirm = store.getters["notice/confirm"]; 30 | confirm.require({ 31 | message, 32 | header: header || 'Tips', 33 | icon: icon||'pi pi-exclamation-triangle', 34 | rejectProps: { 35 | label: 'Cancel', 36 | severity: 'secondary', 37 | outlined: true 38 | }, 39 | acceptProps: { 40 | severity: 'danger', 41 | label: 'Ok' 42 | }, 43 | accept: () => { 44 | accept() 45 | }, 46 | reject: () => { 47 | !!cancel && cancel() 48 | } 49 | }) 50 | } 51 | const require = (options) => { 52 | const store = useStore(); 53 | const confirm = store.getters["notice/confirm"]; 54 | confirm.require(options); 55 | } 56 | export default { 57 | remove, 58 | custom, 59 | require 60 | }; -------------------------------------------------------------------------------- /gui/src/utils/dayjs.js: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | import relativeTime from 'dayjs/plugin/relativeTime'; 3 | const extend = (locale) => { 4 | if(locale == 'zh'){ 5 | dayjs.locale('zh', { 6 | relativeTime: { 7 | future: '%s', 8 | past: '%s', 9 | s: '刚刚', 10 | m: '1 分钟前', 11 | mm: '%d 分钟前', 12 | h: '1 小时前', 13 | hh: '%d 小时前', 14 | d: '1 天前', 15 | dd: '%d 天前', 16 | M: '1 月前', 17 | MM: '%d 月前', 18 | y: '1 年前', 19 | yy: '%d 年前', 20 | } 21 | }); 22 | } else { 23 | dayjs.locale('en', { 24 | relativeTime: { 25 | future: 'in %s', 26 | past: '%s', 27 | s: 'just', 28 | m: '1 min', 29 | mm: '%d mins', 30 | h: '1 hour', 31 | hh: '%d hours', 32 | d: '1 day', 33 | dd: '%d days', 34 | M: '1 mth', 35 | MM: '%d mths', 36 | y: '1 year', 37 | yy: '%d years', 38 | } 39 | }); 40 | } 41 | dayjs.extend(relativeTime) 42 | } 43 | 44 | export { 45 | dayjs, extend 46 | } -------------------------------------------------------------------------------- /gui/src/utils/localStore.js: -------------------------------------------------------------------------------- 1 | import { invoke } from '@tauri-apps/api/core'; 2 | 3 | export const setItem = (key, value, callback) => { 4 | if(!!window.__TAURI_INTERNALS__ ){ 5 | invoke('set_store_list',{ key, value}).then((res)=> callback()); 6 | } else { 7 | localStorage.setItem(key, JSON.stringify(value)) 8 | callback() 9 | } 10 | } 11 | 12 | export const getItem = (key, callback) => { 13 | if(!!window.__TAURI_INTERNALS__ ){ 14 | invoke('get_store_list',{ key }).then((res)=>callback(res)); 15 | } else { 16 | callback(JSON.parse(localStorage.getItem(key))) 17 | } 18 | } -------------------------------------------------------------------------------- /gui/src/utils/notification.js: -------------------------------------------------------------------------------- 1 | import toast from "@/utils/toast"; 2 | import { 3 | isPermissionGranted, 4 | requestPermission, 5 | sendNotification, 6 | createChannel, 7 | Importance, 8 | Visibility, 9 | channels, 10 | } from '@tauri-apps/plugin-notification' 11 | 12 | //toast.add({ severity: 'contrast', summary: 'Tips', detail: "Deleted", life: 3000 }); 13 | const channelId = 'ztm-messages'; 14 | const checkPermission = async () => { 15 | if (!(await isPermissionGranted())) { 16 | return (await requestPermission()) === 'granted' 17 | } 18 | return true 19 | } 20 | 21 | const send = async (title, body) => { 22 | if(!!window.__TAURI_INTERNALS__){ 23 | if (!(await checkPermission())) { 24 | toast.add({ severity: 'contrast', summary: title, detail: body, life: 3000 }); 25 | return 26 | } 27 | sendNotification({ 28 | channelId, 29 | title, 30 | body 31 | }) 32 | } else { 33 | toast.add({ severity: 'contrast', summary: title, detail: body, life: 3000 }); 34 | } 35 | } 36 | const reg = async () => { 37 | 38 | if(!!window.__TAURI_INTERNALS__){ 39 | if (await checkPermission()) { 40 | let has = false; 41 | const notificationChannels = await channels(); 42 | notificationChannels.forEach((channel)=>{ 43 | if(channel.id == channelId){ 44 | has = true; 45 | } 46 | }); 47 | if(!has){ 48 | createChannel({ 49 | id: channelId, 50 | name: 'ZTM Messages', 51 | lights: true, 52 | vibration: true, 53 | importance: Importance.High, 54 | visibility: Visibility.Private 55 | }); 56 | } 57 | } 58 | } 59 | } 60 | export { 61 | send, reg 62 | }; -------------------------------------------------------------------------------- /gui/src/utils/platform.js: -------------------------------------------------------------------------------- 1 | import { platform as platformOs } from '@tauri-apps/plugin-os'; 2 | const platform = (text)=>{ 3 | if(!window.__TAURI_INTERNALS__ ){ 4 | return 'web' 5 | } else { 6 | return platformOs(); 7 | } 8 | } 9 | function isSafariOrMacOS() { 10 | const ua = navigator.userAgent; 11 | const vendor = navigator.vendor; 12 | const platform = navigator.platform; 13 | 14 | const isSafari = /Safari/.test(ua) && /Apple Computer/.test(vendor) && !/Chrome/.test(ua); 15 | const isMacOS = /Macintosh|MacIntel|MacPPC|Mac68K/.test(platform); 16 | 17 | return isSafari || isMacOS; 18 | } 19 | 20 | 21 | const isPC = ()=>{ 22 | const pm = platform(); 23 | return pm != 'ios' && pm != 'android' && pm != 'web'; 24 | } 25 | 26 | export { 27 | platform, isSafariOrMacOS, isPC 28 | }; -------------------------------------------------------------------------------- /gui/src/utils/toast.js: -------------------------------------------------------------------------------- 1 | import store from '@/store'; 2 | const add = (option) => { 3 | const toast = store.getters["notice/toast"]; 4 | toast.add(option) 5 | } 6 | 7 | export default { 8 | add 9 | }; -------------------------------------------------------------------------------- /gui/src/utils/window.js: -------------------------------------------------------------------------------- 1 | import { getCurrentWindow, LogicalSize, LogicalPosition } from '@tauri-apps/api/window'; 2 | import { invoke } from '@tauri-apps/api/core'; 3 | import { platform } from '@tauri-apps/plugin-os'; 4 | 5 | const resize = (width,height,resizable) => { 6 | if(!!window.__TAURI_INTERNALS__ 7 | && platform() != 'android' 8 | && platform() != 'ios' ){ 9 | if(getCurrentWindow().setSize){ 10 | // const label = window.__TAURI_INTERNALS__.metadata.currentWindow.label; 11 | getCurrentWindow().setSize(new LogicalSize(width, height)); 12 | // invoke('plugin:window|set_size', { 13 | // label, 14 | // value: { 15 | // 'Logical': {width,height} 16 | // } 17 | // }); 18 | } 19 | if(getCurrentWindow().setResizable){ 20 | getCurrentWindow().setResizable(resizable); 21 | } 22 | } 23 | } 24 | 25 | const position = (width,height) => { 26 | if(!!window.__TAURI_INTERNALS__ 27 | && platform() != 'android' 28 | && platform() != 'ios' ){ 29 | if(getCurrentWindow().setPosition){ 30 | getCurrentWindow().setPosition(new LogicalPosition(width,height)); 31 | } 32 | } 33 | } 34 | 35 | export { 36 | resize, position 37 | }; -------------------------------------------------------------------------------- /gui/src/views/apps/AppStore.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | -------------------------------------------------------------------------------- /gui/src/views/apps/core/TermContent.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 59 | -------------------------------------------------------------------------------- /gui/src/views/others/Documentation.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 49 | -------------------------------------------------------------------------------- /gui/src/views/pages/auth/Access.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 27 | -------------------------------------------------------------------------------- /gui/src/views/pages/auth/Error.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 27 | -------------------------------------------------------------------------------- /gui/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url'; 2 | import { defineConfig, loadEnv } from 'vite'; 3 | import vue from '@vitejs/plugin-vue'; 4 | import { resolve } from 'path'; 5 | import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'; 6 | 7 | const mobile = !!/android|ios/.exec(process.env.TAURI_ENV_PLATFORM); 8 | const host = process.env.TAURI_DEV_HOST; 9 | 10 | export default defineConfig(async (config) => { 11 | return { 12 | clearScreen: false, 13 | optimizeDeps: { 14 | dynamicImportVars: true, 15 | }, 16 | server: { 17 | port: 1420, 18 | strictPort: true, 19 | host: host || false, 20 | hmr: mobile 21 | ? { 22 | protocol: "ws", 23 | host: host, 24 | port: 1421, 25 | } 26 | : undefined, 27 | watch: { 28 | // 3. tell vite to ignore watching `src-tauri` 29 | ignored: ["**/src-tauri/**"], 30 | }, 31 | proxy: { 32 | '/api': { 33 | target: `http://0.0.0.0:${loadEnv(config.mode, process.cwd()).VITE_APP_API_PORT}/`, 34 | changeOrigin: true, 35 | }, 36 | } 37 | }, 38 | plugins: [ 39 | vue({reactivityTransform: true}), 40 | createSvgIconsPlugin({ 41 | iconDirs: [resolve(process.cwd(), './src/assets/svg')], 42 | symbolId: 'svg-[name]', 43 | }), 44 | ], 45 | resolve: { 46 | alias: { 47 | '@': fileURLToPath(new URL('./src', import.meta.url)) 48 | } 49 | } 50 | } 51 | }); 52 | -------------------------------------------------------------------------------- /hub/options.js: -------------------------------------------------------------------------------- 1 | export default function (argv, { defaults, shorthands }) { 2 | var args = [] 3 | var opts = {} 4 | var lastOption 5 | 6 | argv.forEach( 7 | function (term, i) { 8 | if (i === 0) return 9 | if (lastOption) { 10 | if (term.startsWith('-')) throw `Value missing for option ${lastOption}` 11 | addOption(lastOption, term) 12 | lastOption = undefined 13 | } else if (term.startsWith('--')) { 14 | var kv = term.split('=') 15 | processOption(kv[0], kv[1]) 16 | } else if (term.startsWith('-')) { 17 | if (term.length === 2) { 18 | processOption(term) 19 | } else { 20 | processOption(term.substring(0, 2), term.substring(2)) 21 | } 22 | } else { 23 | args.push(term) 24 | } 25 | } 26 | ) 27 | 28 | function processOption(name, value) { 29 | var k = shorthands[name] || name 30 | if (!(k in defaults)) throw `invalid option ${k}` 31 | if (typeof defaults[k] === 'boolean') { 32 | opts[k] = true 33 | } else if (value) { 34 | addOption(k, value) 35 | } else { 36 | lastOption = name 37 | } 38 | } 39 | 40 | function addOption(name, value) { 41 | var k = shorthands[name] || name 42 | switch (typeof defaults[k]) { 43 | case 'number': opts[k] = Number.parseFloat(value); break 44 | case 'string': opts[k] = value; break 45 | case 'object': (opts[k] ??= []).push(value); break 46 | } 47 | } 48 | 49 | return { args, ...defaults, ...opts } 50 | } 51 | --------------------------------------------------------------------------------