Initial commit: abyssVpn project

- Tauri desktop app (apps/desktop)
- Python Django API service (services/api)
- Deployment scripts and docs
This commit is contained in:
arthur_chen
2026-05-15 09:06:10 +08:00
commit f69efb67ad
146 changed files with 18039 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
# Generated by Cargo
# will have compiled files and executables
/target/
/gen/schemas
+5903
View File
File diff suppressed because it is too large Load Diff
+29
View File
@@ -0,0 +1,29 @@
[package]
name = "app"
version = "0.1.0"
description = "A Tauri App"
authors = ["you"]
license = ""
repository = ""
edition = "2021"
rust-version = "1.77.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2.5.6", features = [] }
[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
log = "0.4"
tauri = { version = "2.10.3", features = ["tray-icon"] }
tokio = { version = "1", features = ["rt-multi-thread"] }
tauri-plugin-log = "2"
tauri-plugin-deep-link = "2.4.3"
tauri-plugin-opener = "2.5.3"
md5 = "0.7"
+40
View File
@@ -0,0 +1,40 @@
fn main() {
let mut windows = tauri_build::WindowsAttributes::new();
if !tauri_build::is_dev() {
windows = windows.app_manifest(
r#"
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>
</assembly>
"#,
);
}
tauri_build::try_build(tauri_build::Attributes::new().windows_attributes(windows))
.expect("failed to run build script");
}
@@ -0,0 +1,25 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "enables the default permissions",
"windows": [
"main",
"logs"
],
"permissions": [
"core:default",
"core:event:default",
"core:window:allow-hide",
"core:window:allow-minimize",
"core:window:allow-start-dragging",
"core:window:allow-create",
"core:window:allow-close",
"core:window:allow-set-focus",
"core:webview:allow-create-webview-window",
"deep-link:default",
"deep-link:allow-is-registered",
"deep-link:allow-register",
"opener:default",
"opener:allow-open-url"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
</assembly>
+1
View File
@@ -0,0 +1 @@
1 24 "resources/app.manifest"
@@ -0,0 +1,14 @@
# Netclient assets
Run `scripts/download-netclient-assets.bat` on Windows or `pwsh scripts/download-netclient-assets.ps1` before building the desktop app.
Expected files:
- `windows/netclientbundle.exe`
- `windows/netclient-windows-amd64.exe`
- `macos/Netclient-M1.pkg`
- `macos/Netclient-Intel.pkg`
- `macos/netclient-darwin-arm64`
- `macos/netclient-darwin-amd64`
The app first looks for an installed `netclient`, then falls back to the bundled binary. If `netclient` is missing, the install button starts the bundled installer with administrator privileges.
@@ -0,0 +1,2 @@
pub mod vpn;
File diff suppressed because it is too large Load Diff
+32
View File
@@ -0,0 +1,32 @@
mod commands;
mod tray;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_opener::init())
.plugin(tauri_plugin_deep_link::init())
.invoke_handler(tauri::generate_handler![
commands::vpn::connect_vpn,
commands::vpn::disconnect_vpn,
commands::vpn::reset_vpn,
commands::vpn::install_netclient,
commands::vpn::vpn_status
])
.setup(|app| {
tray::setup_tray(app)?;
if cfg!(debug_assertions) {
app.handle().plugin(
tauri_plugin_log::Builder::default()
.level(log::LevelFilter::Info)
.build(),
)?;
}
Ok(())
})
.on_window_event(|window, event| {
tray::handle_window_event(window, event);
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
+6
View File
@@ -0,0 +1,6 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
app_lib::run();
}
+69
View File
@@ -0,0 +1,69 @@
use tauri::{
menu::{Menu, MenuItem},
tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
App, AppHandle, Manager, Runtime, WindowEvent,
};
const MENU_SHOW: &str = "show";
const MENU_HIDE: &str = "hide";
const MENU_QUIT: &str = "quit";
pub fn setup_tray(app: &mut App) -> tauri::Result<()> {
let show = MenuItem::with_id(app, MENU_SHOW, "显示窗口", true, None::<&str>)?;
let hide = MenuItem::with_id(app, MENU_HIDE, "隐藏到托盘/菜单栏", true, None::<&str>)?;
let quit = MenuItem::with_id(app, MENU_QUIT, "退出", true, None::<&str>)?;
let menu = Menu::with_items(app, &[&show, &hide, &quit])?;
let mut builder = TrayIconBuilder::new()
.tooltip("AbyssInfo VPN")
.menu(&menu)
.show_menu_on_left_click(false)
.on_menu_event(|app, event| match event.id.as_ref() {
MENU_SHOW => show_main_window(app),
MENU_HIDE => hide_main_window(app),
MENU_QUIT => app.exit(0),
_ => {}
})
.on_tray_icon_event(|tray, event| match event {
TrayIconEvent::Click {
button: MouseButton::Left,
button_state: MouseButtonState::Up,
..
}
| TrayIconEvent::DoubleClick {
button: MouseButton::Left,
..
} => show_main_window(tray.app_handle()),
_ => {}
});
if let Some(icon) = app.default_window_icon() {
builder = builder.icon(icon.clone());
}
builder.build(app)?;
Ok(())
}
pub fn handle_window_event<R: Runtime>(window: &tauri::Window<R>, event: &WindowEvent) {
if let WindowEvent::CloseRequested { api, .. } = event {
api.prevent_close();
let _ = window.hide();
let _ = window.set_skip_taskbar(true);
}
}
fn show_main_window<R: Runtime>(app: &AppHandle<R>) {
if let Some(window) = app.get_webview_window("main") {
let _ = window.set_skip_taskbar(false);
let _ = window.show();
let _ = window.set_focus();
}
}
fn hide_main_window<R: Runtime>(app: &AppHandle<R>) {
if let Some(window) = app.get_webview_window("main") {
let _ = window.hide();
let _ = window.set_skip_taskbar(true);
}
}
+54
View File
@@ -0,0 +1,54 @@
{
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
"productName": "AbyssInfo VPN",
"version": "0.1.0",
"identifier": "com.abyssinfo.homevpn",
"build": {
"frontendDist": "../dist",
"devUrl": "http://localhost:5173",
"beforeDevCommand": "npm run dev",
"beforeBuildCommand": "npm run build"
},
"app": {
"windows": [
{
"title": "AbyssInfo VPN",
"width": 390,
"height": 760,
"minWidth": 360,
"minHeight": 640,
"maxWidth": 430,
"resizable": true,
"decorations": false,
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
"fullscreen": false
}
],
"security": {
"csp": null
}
},
"plugins": {
"deep-link": {
"desktop": {
"schemes": [
"myvpn"
]
}
}
},
"bundle": {
"active": true,
"targets": "all",
"resources": [
"resources/**/*"
],
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
}
}