|
15 | 15 | > |
16 | 16 | <ElTableColumn |
17 | 17 | sortable |
18 | | - width="140" |
19 | 18 | label="成员名" |
20 | 19 | prop="hostname" |
21 | 20 | > |
22 | 21 | <template #default="{ row }"> |
23 | | - {{ |
24 | | - (row.hostname || "").toLowerCase().includes("publicserver") |
25 | | - ? (row.hostname || "").replace("PublicServer", "服务器") |
26 | | - : row.hostname || "-" |
27 | | - }} |
| 22 | + <div class="whitespace-pre-wrap"> |
| 23 | + <div> |
| 24 | + {{ |
| 25 | + (row.hostname || "").toLowerCase().includes("publicserver") |
| 26 | + ? (row.hostname || "").replace("PublicServer", "服务器") |
| 27 | + : row.hostname || "-" |
| 28 | + }} |
| 29 | + </div> |
| 30 | + <div |
| 31 | + class="space-y-1" |
| 32 | + v-if="row?.connections_addrs?.length > 0" |
| 33 | + > |
| 34 | + <ElTag |
| 35 | + :key="url" |
| 36 | + v-for="url in row.connections_addrs" |
| 37 | + class="!flex !h-auto !whitespace-pre-wrap !break-all !py-[5px]" |
| 38 | + > |
| 39 | + {{ url }} |
| 40 | + </ElTag> |
| 41 | + </div> |
| 42 | + </div> |
28 | 43 | </template> |
29 | 44 | </ElTableColumn> |
30 | 45 | <ElTableColumn |
|
127 | 142 | import { ElConfirmDanger } from "~/utils/element"; |
128 | 143 | import { getCurrentWindow } from "@tauri-apps/api/window"; |
129 | 144 | import { endsWith, isNaN } from "lodash-es"; |
130 | | - // enum NatType { |
131 | | - // // has NAT; but own a single public IP, port is not changed |
132 | | - // Unknown = 0; |
133 | | - // OpenInternet = 1; |
134 | | - // NoPAT = 2; |
135 | | - // FullCone = 3; |
136 | | - // Restricted = 4; |
137 | | - // PortRestricted = 5; |
138 | | - // Symmetric = 6; |
139 | | - // SymUdpFirewall = 7; |
140 | | - // SymmetricEasyInc = 8; |
141 | | - // SymmetricEasyDec = 9; |
142 | | - // } |
| 145 | +
|
| 146 | + type Member = { |
| 147 | + cidr: string; |
| 148 | + ipv4: string; |
| 149 | + hostname: string; |
| 150 | + cost: string; |
| 151 | + lat_ms: string; |
| 152 | + loss_rate: string; |
| 153 | + rx_bytes: string; |
| 154 | + tx_bytes: string; |
| 155 | + tunnel_proto: string; |
| 156 | + nat_type: string; |
| 157 | + id: string; |
| 158 | + version: string; |
| 159 | + connections_addrs: string[]; |
| 160 | + }; |
| 161 | +
|
| 162 | + type ConnectionsType = { |
| 163 | + route: { |
| 164 | + peer_id: number; |
| 165 | + ipv4_addr: string | null; |
| 166 | + next_hop_peer_id: number; |
| 167 | + cost: number; |
| 168 | + path_latency: number; |
| 169 | + proxy_cidrs: string[]; |
| 170 | + hostname: string; |
| 171 | + stun_info: { |
| 172 | + udp_nat_type: number; |
| 173 | + tcp_nat_type: number; |
| 174 | + last_update_time: number; |
| 175 | + public_ip: string[]; |
| 176 | + min_port: number; |
| 177 | + max_port: number; |
| 178 | + }; |
| 179 | + }; |
| 180 | + peer: { |
| 181 | + peer_id: number; |
| 182 | + conns: { |
| 183 | + conn_id: string; |
| 184 | + my_peer_id: number; |
| 185 | + peer_id: number; |
| 186 | + features: string[]; |
| 187 | + tunnel: { |
| 188 | + tunnel_type: string; |
| 189 | + local_addr: { |
| 190 | + url: string; |
| 191 | + }; |
| 192 | + remote_addr: { |
| 193 | + url: string; |
| 194 | + }; |
| 195 | + }; |
| 196 | + }[]; |
| 197 | + }; |
| 198 | + }; |
| 199 | +
|
143 | 200 | const natMaps = { |
144 | 201 | unknown: "未知", |
145 | 202 | OpenInternet: "nat0-openinternet", |
|
154 | 211 | }; |
155 | 212 | type natKyes = keyof typeof natMaps; |
156 | 213 |
|
157 | | - const data = reactive<{ member: { hostname: string; cost: string; ipv4: string; lat_msg: string; loss_rate: string; nat_type: string }[] }>({ |
| 214 | + const data = reactive<{ member: Member[] }>({ |
158 | 215 | member: [] |
159 | 216 | }); |
160 | 217 |
|
161 | 218 | // 延迟排序函数 |
162 | | - const sortLatMs = (a: any, b: any): number => { |
163 | | - const getLatencyValue = (row: any): number => { |
| 219 | + const sortLatMs = (a: Member, b: Member): number => { |
| 220 | + const getLatencyValue = (row: Member): number => { |
164 | 221 | const latMs = row.lat_ms; |
165 | 222 |
|
166 | 223 | if (latMs === null || latMs === undefined || latMs === "") { |
|
298 | 355 | return num.toFixed(0); |
299 | 356 | }; |
300 | 357 |
|
301 | | - const _showTableHeader = [ |
302 | | - ["hostname", "主机名"], |
303 | | - ["cost", "路由"], |
304 | | - ["ipv4", "虚拟网IP"], |
305 | | - ["lat_ms", "延迟/ms"], |
306 | | - ["loss_rate", "丢包率"], |
307 | | - ["nat_type", "NAT类型"], |
308 | | - ["version", "版本"], |
309 | | - ["tunnel_proto", "隧道协议"], |
310 | | - ["rx_bytes", "接收"], |
311 | | - ["tx_bytes", "传输"] |
312 | | - ]; |
313 | | -
|
314 | 358 | let timer: number | null = null; |
315 | 359 |
|
316 | 360 | const listenOutput = async () => { |
|
334 | 378 | } |
335 | 379 | return; |
336 | 380 | } |
337 | | - // const peerInfo = parseCliInfo(member); |
338 | | - // peerInfo.forEach(value => { |
339 | | - // if (value.cost === "Local") { |
340 | | - // value.cost = "本机"; |
341 | | - // } |
342 | | - // if (value.ipv4 && value.ipv4.includes("/")) { |
343 | | - // value.ipv4 = value.ipv4.split("/")[0]; |
344 | | - // } |
345 | | - // }); |
346 | | - // data.member = peerInfo; |
347 | | -
|
348 | | - data.member = JSON.parse(member); |
| 381 | + const [errorConnections, connections] = await ATJ(invoke<string>("get_members_connections_cli")); |
| 382 | + const memberConnections: ConnectionsType[] = JSON.parse(connections) as ConnectionsType[]; |
| 383 | +
|
| 384 | + if (errorConnections != "_EasytierGameCliFailedToGetConnections_") { |
| 385 | + data.member = (JSON.parse(member) as Member[]).map(member => { |
| 386 | + const connection = memberConnections.find(conn => String(conn.route.peer_id) === member.id); |
| 387 | + if (connection) { |
| 388 | + member.connections_addrs = connection?.peer?.conns?.map(conn => conn?.tunnel?.remote_addr?.url || "") || []; |
| 389 | + } else { |
| 390 | + member.connections_addrs = []; |
| 391 | + } |
| 392 | + return member; |
| 393 | + }); |
| 394 | + } else { |
| 395 | + data.member = JSON.parse(member) as Member[]; |
| 396 | + } |
| 397 | + // console.log(data.member); |
349 | 398 | startTimer(); |
350 | 399 | }; |
351 | 400 |
|
|
0 commit comments