From ebab70ca3b843ad51c86a1d37427273bd45f8cb3 Mon Sep 17 00:00:00 2001 From: "Sijie.Sun" Date: Wed, 25 Jun 2025 09:03:47 +0800 Subject: [PATCH] add geo info for in web device list (#1052) --- Cargo.lock | 15 ++ easytier-web/Cargo.toml | 5 +- easytier-web/frontend-lib/src/locales/cn.yaml | 1 + easytier-web/frontend-lib/src/locales/en.yaml | 3 +- .../frontend-lib/src/modules/utils.ts | 8 + .../frontend/src/components/DeviceList.vue | 64 ++++++-- easytier-web/locales/app.yml | 5 +- easytier-web/resources/geoip2-cn.mmdb | Bin 0 -> 132218 bytes easytier-web/src/client_manager/mod.rs | 140 +++++++++++++++++- easytier-web/src/client_manager/session.rs | 19 ++- easytier-web/src/main.rs | 8 +- easytier-web/src/restful/network.rs | 5 +- 12 files changed, 248 insertions(+), 25 deletions(-) create mode 100644 easytier-web/resources/geoip2-cn.mmdb diff --git a/Cargo.lock b/Cargo.lock index e3ceba8..a591ce7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2133,6 +2133,8 @@ dependencies = [ "easytier", "image 0.24.9", "imageproc", + "maxminddb", + "once_cell", "password-auth", "rand 0.8.5", "rust-embed", @@ -4340,6 +4342,18 @@ dependencies = [ "rawpointer", ] +[[package]] +name = "maxminddb" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6087e5d8ea14861bb7c7f573afbc7be3798d3ef0fae87ec4fd9a4de9a127c3c" +dependencies = [ + "ipnetwork", + "log", + "memchr", + "serde", +] + [[package]] name = "md-5" version = "0.10.6" @@ -6582,6 +6596,7 @@ version = "8.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d" dependencies = [ + "globset", "sha2", "walkdir", ] diff --git a/easytier-web/Cargo.toml b/easytier-web/Cargo.toml index 2356a6e..041aee0 100644 --- a/easytier-web/Cargo.toml +++ b/easytier-web/Cargo.toml @@ -14,6 +14,9 @@ dashmap = "6.1" url = "2.2" async-trait = "0.1" +maxminddb = "0.24" +once_cell = "1.18" + axum = { version = "0.7", features = ["macros"] } axum-login = { version = "0.16" } password-auth = { version = "1.0.0" } @@ -34,7 +37,7 @@ sea-orm-migration = { version = "1.1" } # for captcha -rust-embed = { version = "8.5.0", features = ["debug-embed"] } +rust-embed = { version = "8.5.0", features = ["debug-embed", "include-exclude"] } base64 = "0.22" rand = "0.8" image = { version = "0.24", default-features = false, features = ["png"] } diff --git a/easytier-web/frontend-lib/src/locales/cn.yaml b/easytier-web/frontend-lib/src/locales/cn.yaml index a2731be..96511d5 100644 --- a/easytier-web/frontend-lib/src/locales/cn.yaml +++ b/easytier-web/frontend-lib/src/locales/cn.yaml @@ -262,6 +262,7 @@ web: last_report: 最后在线 version: 版本 machine_id: 机器ID + unknown_location: 未知位置 device_management: edit_network: 编辑网络 diff --git a/easytier-web/frontend-lib/src/locales/en.yaml b/easytier-web/frontend-lib/src/locales/en.yaml index a567a50..e27aca8 100644 --- a/easytier-web/frontend-lib/src/locales/en.yaml +++ b/easytier-web/frontend-lib/src/locales/en.yaml @@ -262,7 +262,8 @@ web: last_report: Last Seen version: Version machine_id: Machine ID - + unknown_location: Unknown Location + device_management: edit_network: Edit Network export_config: Export Config diff --git a/easytier-web/frontend-lib/src/modules/utils.ts b/easytier-web/frontend-lib/src/modules/utils.ts index 1ea667b..c6fc514 100644 --- a/easytier-web/frontend-lib/src/modules/utils.ts +++ b/easytier-web/frontend-lib/src/modules/utils.ts @@ -53,6 +53,12 @@ export function UuidToStr(uuid: UUID): string { return uint32ToUuid(uuid.part1, uuid.part2, uuid.part3, uuid.part4); } +export interface Location { + country: string | undefined; + city: string | undefined; + region: string | undefined; +} + export interface DeviceInfo { hostname: string; public_ip: string; @@ -61,6 +67,7 @@ export interface DeviceInfo { easytier_version: string; running_network_instances?: Array; machine_id: string; + location: Location | undefined; } export function buildDeviceInfo(device: any): DeviceInfo { @@ -72,6 +79,7 @@ export function buildDeviceInfo(device: any): DeviceInfo { report_time: device.info?.report_time, easytier_version: device.info?.easytier_version, machine_id: UuidToStr(device.info?.machine_id), + location: device.location, }; return dev_info; diff --git a/easytier-web/frontend/src/components/DeviceList.vue b/easytier-web/frontend/src/components/DeviceList.vue index e2884f5..ce81766 100644 --- a/easytier-web/frontend/src/components/DeviceList.vue +++ b/easytier-web/frontend/src/components/DeviceList.vue @@ -42,15 +42,7 @@ const loadDevices = async () => { const resp = await api?.list_machines(); let devices: Array = []; for (const device of (resp || [])) { - devices.push({ - hostname: device.info?.hostname, - public_ip: device.client_url, - running_network_instances: device.info?.running_network_instances.map((instance: any) => Utils.UuidToStr(instance)), - running_network_count: device.info?.running_network_instances.length, - report_time: new Date(device.info?.report_time).toLocaleString(), - easytier_version: device.info?.easytier_version, - machine_id: Utils.UuidToStr(device.info?.machine_id), - }); + devices.push(Utils.buildDeviceInfo(device)); } console.debug("device list", deviceList.value); deviceList.value = devices; @@ -666,6 +658,37 @@ const handleResize = () => { width: 2.5rem; height: 2.5rem; } + +/* 位置样式 */ +.location-icon { + color: var(--pink-500); + font-size: 0.9rem; +} + +.location-text { + font-size: 0.875rem; + line-height: 1.25rem; + opacity: 0.9; + display: inline-flex; + align-items: center; + gap: 0.25rem; +} + +.location-separator { + opacity: 0.5; + font-weight: 300; + margin: 0 0.1rem; +} + +@media (prefers-color-scheme: dark) { + .location-text { + color: var(--text-color-secondary, #cbd5e1); + } + + .location-icon { + color: var(--pink-400); + } +}