refactor: show all IP addresses in device info

This commit is contained in:
wj-xiao
2025-04-03 15:59:59 +08:00
parent 49220d8024
commit 43d6002542
4 changed files with 155 additions and 15 deletions

View File

@@ -1,7 +1,14 @@
package proto
type IP struct {
Name string `json:"name"`
Addr string `json:"addr"`
Version string `json:"version"`
Type string `json:"type"`
}
type GetInfoRsp struct {
Ip string `json:"ip"`
IPs []IP `json:"ips"`
Mdns string `json:"mdns"`
Image string `json:"image"`
Application string `json:"application"`

View File

@@ -3,7 +3,6 @@ package vm
import (
"NanoKVM-Server/config"
"fmt"
"net"
"os"
"strings"
@@ -25,7 +24,7 @@ func (s *Service) GetInfo(c *gin.Context) {
var rsp proto.Response
data := &proto.GetInfoRsp{
Ip: getIp(),
IPs: getIPs(),
Mdns: getMdns(),
Image: getImageVersion(),
Application: getApplicationVersion(),
@@ -36,20 +35,24 @@ func (s *Service) GetInfo(c *gin.Context) {
log.Debug("get vm information success")
}
func getIp() string {
addressList, err := net.InterfaceAddrs()
func getIPs() (ips []proto.IP) {
interfaces, err := GetInterfaceInfos()
if err != nil {
return ""
return
}
for _, address := range addressList {
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && ipnet.IP.To4() != nil {
ip := ipnet.IP.String()
return ip
for _, iface := range interfaces {
if iface.IP.To4() != nil {
ips = append(ips, proto.IP{
Name: iface.Name,
Addr: iface.IP.String(),
Version: "IPv4",
Type: iface.Type,
})
}
}
return ""
return
}
func getMdns() string {

107
server/service/vm/ip.go Normal file
View File

@@ -0,0 +1,107 @@
package vm
import (
"fmt"
"net"
"strings"
log "github.com/sirupsen/logrus"
)
const (
Wired = "Wired"
Wireless = "Wireless"
Other = "Other"
)
type InterfaceInfo struct {
Name string
Type string
IP net.IP
}
func GetInterfaceInfos() ([]*InterfaceInfo, error) {
var interfaceInfos []*InterfaceInfo
interfaces, err := net.Interfaces()
if err != nil {
log.Errorf("failed to get net interfaces: %s", err)
return nil, err
}
for _, iface := range interfaces {
info := getInterfaceInfo(iface)
if info != nil {
interfaceInfos = append(interfaceInfos, info)
}
}
if len(interfaceInfos) == 0 {
return nil, fmt.Errorf("no valid IP address")
}
return interfaceInfos, nil
}
func getInterfaceInfo(iface net.Interface) *InterfaceInfo {
if iface.Flags&net.FlagUp == 0 {
return nil
}
interfaceType := getInterfaceType(iface)
if interfaceType == Other {
return nil
}
interfaceIP := getInterfaceIP(iface)
if interfaceIP == nil {
return nil
}
return &InterfaceInfo{
Name: iface.Name,
Type: interfaceType,
IP: interfaceIP,
}
}
func getInterfaceType(iface net.Interface) string {
if strings.HasPrefix(iface.Name, "eth") || strings.HasPrefix(iface.Name, "en") {
return Wired
}
if strings.HasPrefix(iface.Name, "wlan") || strings.HasPrefix(iface.Name, "wl") {
return Wireless
}
return Other
}
func getInterfaceIP(iface net.Interface) net.IP {
addrs, err := iface.Addrs()
if err != nil {
log.Errorf("failed to get interface addresses: %s", err)
return nil
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
default:
continue
}
if ip == nil {
continue
}
return ip
}
return nil
}

View File

@@ -1,12 +1,19 @@
import { useEffect, useState } from 'react';
import { Tooltip } from 'antd';
import { Tag, Tooltip } from 'antd';
import { CircleHelpIcon } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import * as api from '@/api/vm.ts';
type IP = {
name: string;
addr: string;
version: string;
type: string;
};
type Info = {
ip: string;
ips: IP[];
mdns: string;
image: string;
application: string;
@@ -34,11 +41,24 @@ export const Information = () => {
<div className="pb-5 text-neutral-400">{t('settings.about.information')}</div>
<div className="flex w-full flex-col space-y-4">
<div className="flex w-full items-center justify-between">
{/* IP list */}
<div className="flex w-full items-start justify-between">
<span>{t('settings.about.ip')}</span>
<span>{information ? information.ip : '-'}</span>
{information?.ips && information.ips.length > 0 ? (
<div className="flex flex-col space-y-1">
{information.ips.map((ip) => (
<div className="flex items-center space-x-1">
<span>{ip.addr}</span>
<Tag>{ip.type}</Tag>
</div>
))}
</div>
) : (
<span>-</span>
)}
</div>
{/* mDNS */}
{!!information?.mdns && (
<div className="flex w-full items-center justify-between">
<span>{t('settings.about.mdns')}</span>
@@ -46,6 +66,7 @@ export const Information = () => {
</div>
)}
{/* image version */}
<div className="flex w-full items-center justify-between">
<div className="flex items-center space-x-2">
<span>{t('settings.about.image')}</span>
@@ -61,6 +82,7 @@ export const Information = () => {
<span>{information ? information.image : '-'}</span>
</div>
{/* application version */}
<div className="flex w-full items-center justify-between">
<div className="flex items-center space-x-2">
<span>{t('settings.about.application')}</span>
@@ -76,6 +98,7 @@ export const Information = () => {
<span>{information ? information.application : '-'}</span>
</div>
{/* device key */}
<div className="flex w-full items-center justify-between">
<span>{t('settings.about.deviceKey')}</span>
<span>{information ? information.deviceKey : '-'}</span>