├── .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 |
2 |
3 |
4 |
5 |
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 |
12 |
19 |
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 |
2 |
3 |
4 |
5 |
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 |
2 |
3 |
4 |
5 |
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 |
2 |
3 |
4 |
5 |
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 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/gui/src/components/common/Avatar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
![]()
4 |
5 |
6 |
7 |
53 |
54 |
--------------------------------------------------------------------------------
/gui/src/components/common/BaseCard.vue:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/gui/src/components/common/Card.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
42 |
43 |
--------------------------------------------------------------------------------
/gui/src/components/common/DataViewLayoutOptions.vue:
--------------------------------------------------------------------------------
1 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/gui/src/components/common/DrawMenu.vue:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 |
23 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/gui/src/components/common/Ep.vue:
--------------------------------------------------------------------------------
1 |
27 |
28 |
29 | {{endpoint?.name||'...'}}
30 |
31 |
32 |
--------------------------------------------------------------------------------
/gui/src/components/common/FloatField.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | {{errorMessage}}
16 |
17 |
18 |
--------------------------------------------------------------------------------
/gui/src/components/common/FormItem.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 | {{props.label}}
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/gui/src/components/common/HiddenField.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 | {{errorMessage}}
13 |
14 |
15 |
--------------------------------------------------------------------------------
/gui/src/components/editor/JsEditor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
15 |
63 |
--------------------------------------------------------------------------------
/gui/src/components/editor/ShellEditor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
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 |
10 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/gui/src/layout/AppMenu.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/gui/src/layout/AppSidebar.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
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 |
25 |
28 |
--------------------------------------------------------------------------------
/gui/src/views/apps/core/TermContent.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
59 |
--------------------------------------------------------------------------------
/gui/src/views/others/Documentation.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
一、启动 xeye 服务
5 |
6 | 需要在运行服务的机器上先安装 pipy、openssl(3.0以上版本)这2个可执行程序,另外,9090、6060 这2个端口需要可用。
7 |
8 |
9 |
1. 下载工程
10 |
git clone https://github.com/polaristech-io/xeye.git
11 |
12 |
2. 启动服务
13 |
cd xeye/client
14 | pipy pjs/main.js
15 |
16 |
二、使用浏览器测试效果
17 |
1. 安装CA根证书
18 |
将 CA.crt 证书安装到系统,或者安装到浏览器。
19 |
20 |
2. 给浏览器设置 http、https 代理
21 |
代理地址 xeye服务地址:9090。
22 |
23 |
3. 浏览器访问
24 |
访问 https//flomesh.io/ 等网站。
25 |
26 |
4. 查看 xeye GUI 网页
27 |
浏览器访问 http://xeye服务地址:6060/。
28 |
29 |
30 |
31 |
49 |
--------------------------------------------------------------------------------
/gui/src/views/pages/auth/Access.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Access Denied
15 |
You do not have the necessary permisions. Please contact admins.
16 |
![Access denied]()
17 |
18 |
19 | Go to Dashboard
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/gui/src/views/pages/auth/Error.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Error Occured
15 |
Requested resource is not available.
16 |
![Error]()
17 |
18 |
19 | Go to Dashboard
20 |
21 |
22 |
23 |
24 |
25 |
26 |
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 |
--------------------------------------------------------------------------------