mirror of
https://github.com/sipeed/NanoKVM.git
synced 2026-09-11 00:22:56 -05:00
refactor: refactor the Wi-Fi module
This commit is contained in:
@@ -2,24 +2,26 @@
|
|||||||
|
|
||||||
. /etc/profile
|
. /etc/profile
|
||||||
|
|
||||||
|
APFLAG_FILE=/tmp/wifiap
|
||||||
|
|
||||||
gen_hostapd_conf() {
|
gen_hostapd_conf() {
|
||||||
ssid="${1}"
|
ssid="${1}"
|
||||||
pass="${2}"
|
pass="${2}"
|
||||||
echo "ctrl_interface=/var/run/hostapd"
|
echo "ctrl_interface=/var/run/hostapd"
|
||||||
echo "ctrl_interface_group=0"
|
echo "ctrl_interface_group=0"
|
||||||
echo "ssid=${ssid}"
|
echo "ssid=${ssid}"
|
||||||
echo "hw_mode=g"
|
echo "hw_mode=g"
|
||||||
echo "channel=1"
|
echo "channel=1"
|
||||||
echo "beacon_int=100"
|
echo "beacon_int=100"
|
||||||
echo "dtim_period=2"
|
echo "dtim_period=2"
|
||||||
echo "max_num_sta=255"
|
echo "max_num_sta=255"
|
||||||
echo "rts_threshold=-1"
|
echo "rts_threshold=-1"
|
||||||
echo "fragm_threshold=-1"
|
echo "fragm_threshold=-1"
|
||||||
echo "macaddr_acl=0"
|
echo "macaddr_acl=0"
|
||||||
echo "auth_algs=3"
|
echo "auth_algs=3"
|
||||||
echo "wpa=2"
|
echo "wpa=2"
|
||||||
echo "wpa_passphrase=${pass}"
|
echo "wpa_passphrase=${pass}"
|
||||||
echo "ieee80211n=1"
|
echo "ieee80211n=1"
|
||||||
}
|
}
|
||||||
|
|
||||||
gen_udhcpd_conf() {
|
gen_udhcpd_conf() {
|
||||||
@@ -61,19 +63,16 @@ start() {
|
|||||||
chown root:root /etc/kvm/wifi.ssid /etc/kvm/wifi.pass
|
chown root:root /etc/kvm/wifi.ssid /etc/kvm/wifi.pass
|
||||||
chmod 644 /etc/kvm/wifi.ssid /etc/kvm/wifi.pass
|
chmod 644 /etc/kvm/wifi.ssid /etc/kvm/wifi.pass
|
||||||
fi
|
fi
|
||||||
if [ -e /etc/kvm/wifi.ssid ]
|
if [ -e /etc/kvm/wifi.ssid ]; then
|
||||||
then
|
ssid=$(cat /etc/kvm/wifi.ssid)
|
||||||
ssid=`cat /etc/kvm/wifi.ssid`
|
|
||||||
fi
|
fi
|
||||||
if [ -e /etc/kvm/wifi.pass ]
|
if [ -e /etc/kvm/wifi.pass ]; then
|
||||||
then
|
pass=$(cat /etc/kvm/wifi.pass)
|
||||||
pass=`cat /etc/kvm/wifi.pass`
|
|
||||||
fi
|
fi
|
||||||
echo "ctrl_interface=/var/run/wpa_supplicant" > /etc/wpa_supplicant.conf
|
echo "ctrl_interface=/var/run/wpa_supplicant" >/etc/wpa_supplicant.conf
|
||||||
wpa_passphrase "$ssid" "$pass" >> /etc/wpa_supplicant.conf
|
wpa_passphrase "$ssid" "$pass" >>/etc/wpa_supplicant.conf
|
||||||
wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf
|
wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf
|
||||||
if [ ! -e /boot/wifi.nodhcp ]
|
if [ ! -e /boot/wifi.nodhcp ]; then
|
||||||
then
|
|
||||||
(udhcpc -i wlan0 -t 10 -T 1 -A 5 -b -p /run/udhcpc.wlan0.pid) &
|
(udhcpc -i wlan0 -t 10 -T 1 -A 5 -b -p /run/udhcpc.wlan0.pid) &
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -82,33 +81,27 @@ ap_start() {
|
|||||||
echo "wifi mode: ap"
|
echo "wifi mode: ap"
|
||||||
id2=$(printf "%d" 0x$(sha512sum /sys/class/cvi-base/base_uid | head -c 2))
|
id2=$(printf "%d" 0x$(sha512sum /sys/class/cvi-base/base_uid | head -c 2))
|
||||||
id3=$(printf "%d" 0x$(sha512sum /sys/class/cvi-base/base_uid | head -c 4 | tail -c 2))
|
id3=$(printf "%d" 0x$(sha512sum /sys/class/cvi-base/base_uid | head -c 4 | tail -c 2))
|
||||||
if [ "$id2" = "$id3" ]
|
if [ "$id2" = "$id3" ]; then
|
||||||
then
|
|
||||||
id2=$((id2 + 1))
|
id2=$((id2 + 1))
|
||||||
fi
|
fi
|
||||||
if [ "$id2" -ge 255 ]
|
if [ "$id2" -ge 255 ]; then
|
||||||
then
|
|
||||||
id2=253
|
id2=253
|
||||||
fi
|
fi
|
||||||
if [ "$id3" -ge 255 ]
|
if [ "$id3" -ge 255 ]; then
|
||||||
then
|
|
||||||
id3=254
|
id3=254
|
||||||
fi
|
fi
|
||||||
ssid=""
|
ssid=""
|
||||||
pass=""
|
pass=""
|
||||||
if [ -e /kvmapp/kvm/ap.ssid ]
|
if [ -e /kvmapp/kvm/ap.ssid ]; then
|
||||||
then
|
ssid=$(cat /kvmapp/kvm/ap.ssid)
|
||||||
ssid=`cat /kvmapp/kvm/ap.ssid`
|
|
||||||
fi
|
fi
|
||||||
if [ -e /kvmapp/kvm/ap.pass ]
|
if [ -e /kvmapp/kvm/ap.pass ]; then
|
||||||
then
|
pass=$(cat /kvmapp/kvm/ap.pass)
|
||||||
pass=`cat /kvmapp/kvm/ap.pass`
|
|
||||||
fi
|
fi
|
||||||
gen_hostapd_conf "$ssid" "$pass" > /etc/hostapd.conf
|
gen_hostapd_conf "$ssid" "$pass" >/etc/hostapd.conf
|
||||||
ipv4_prefix=10.$id3.$id2
|
ipv4_prefix=10.$id3.$id2
|
||||||
if [ ! -e /etc/udhcpd.wlan0.conf ]
|
if [ ! -e /etc/udhcpd.wlan0.conf ]; then
|
||||||
then
|
gen_udhcpd_conf wlan0 "${ipv4_prefix}" >/etc/udhcpd.wlan0.conf
|
||||||
gen_udhcpd_conf wlan0 "${ipv4_prefix}" > /etc/udhcpd.wlan0.conf
|
|
||||||
fi
|
fi
|
||||||
# gen_dnsmasq_conf "${ipv4_prefix}" > /etc/dnsmasq.conf
|
# gen_dnsmasq_conf "${ipv4_prefix}" > /etc/dnsmasq.conf
|
||||||
|
|
||||||
@@ -126,50 +119,52 @@ ap_start() {
|
|||||||
# dnsmasq --pid-file=/tmp/dnsmasq.run -C /etc/dnsmasq.conf
|
# dnsmasq --pid-file=/tmp/dnsmasq.run -C /etc/dnsmasq.conf
|
||||||
hostapd -B -i wlan0 /etc/hostapd.conf
|
hostapd -B -i wlan0 /etc/hostapd.conf
|
||||||
udhcpd -S /etc/udhcpd.wlan0.conf
|
udhcpd -S /etc/udhcpd.wlan0.conf
|
||||||
|
|
||||||
|
if [ ! -f "$APFLAG_FILE" ]; then
|
||||||
|
touch "$APFLAG_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
ps -ef|grep hostapd|grep -v grep|awk '{print $1}'|xargs kill -2 || true
|
ps -ef | grep hostapd | grep -v grep | awk '{print $1}' | xargs kill -2 || true
|
||||||
ps -ef|grep "udhcpd -S /etc/udhcpd.wlan0.conf" |grep -v grep|awk '{print $1}'|xargs kill -2 || true
|
ps -ef | grep "udhcpd -S /etc/udhcpd.wlan0.conf" | grep -v grep | awk '{print $1}' | xargs kill -2 || true
|
||||||
killall wpa_supplicant || true
|
killall wpa_supplicant || true
|
||||||
if [ -e /run/udhcpc.wlan0.pid ]
|
if [ -e /run/udhcpc.wlan0.pid ]; then
|
||||||
then
|
kill $(cat /run/udhcpc.wlan0.pid) || true
|
||||||
kill `cat /run/udhcpc.wlan0.pid` || true
|
rm -f /run/udhcpc.wlan0.pid
|
||||||
rm -f /run/udhcpc.wlan0.pid
|
fi
|
||||||
fi
|
if [ -e /var/run/udhcpd.wlan0.pid ]; then
|
||||||
if [ -e /var/run/udhcpd.wlan0.pid ]
|
kill $(cat /var/run/udhcpd.wlan0.pid) || true
|
||||||
then
|
rm -f /var/run/udhcpd.wlan0.pid
|
||||||
kill `cat /var/run/udhcpd.wlan0.pid` || true
|
fi
|
||||||
rm -f /var/run/udhcpd.wlan0.pid
|
if [ -e /tmp/dnsmasq.run ]; then
|
||||||
fi
|
kill $(cat /tmp/dnsmasq.run) || true
|
||||||
if [ -e /tmp/dnsmasq.run ]
|
rm -f /tmp/dnsmasq.run
|
||||||
then
|
fi
|
||||||
kill `cat /tmp/dnsmasq.run` || true
|
# if [ -e /etc/wpa_supplicant.conf]
|
||||||
rm -f /tmp/dnsmasq.run
|
# then
|
||||||
fi
|
# echo > /etc/wpa_supplicant.conf
|
||||||
# if [ -e /etc/wpa_supplicant.conf]
|
# fi
|
||||||
# then
|
airmon-ng stop wlan0mon || true
|
||||||
# echo > /etc/wpa_supplicant.conf
|
|
||||||
# fi
|
if [ -f "$APFLAG_FILE" ]; then
|
||||||
airmon-ng stop wlan0mon || true
|
rm "$APFLAG_FILE"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
restart() {
|
restart() {
|
||||||
stop
|
stop
|
||||||
start
|
start
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ "${1}" = "start" ]
|
if [ "${1}" = "start" ]; then
|
||||||
then
|
start
|
||||||
start
|
elif [ "${1}" = "stop" ]; then
|
||||||
elif [ "${1}" = "stop" ]
|
|
||||||
then
|
|
||||||
stop
|
|
||||||
elif [ "${1}" = "ap" ]
|
|
||||||
then
|
|
||||||
stop
|
stop
|
||||||
ap_start
|
elif [ "${1}" = "ap" ]; then
|
||||||
elif [ "${1}" = "restart" ]
|
stop
|
||||||
then
|
ap_start
|
||||||
restart
|
elif [ "${1}" = "restart" ]; then
|
||||||
|
restart
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -21,8 +21,3 @@ type ChangePasswordReq struct {
|
|||||||
type IsPasswordUpdatedRsp struct {
|
type IsPasswordUpdatedRsp struct {
|
||||||
IsUpdated bool `json:"isUpdated"`
|
IsUpdated bool `json:"isUpdated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConnectWifiReq struct {
|
|
||||||
Ssid string `validate:"required"`
|
|
||||||
Password string `valid:"required"`
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -17,28 +17,14 @@ type SetMacNameReq struct {
|
|||||||
Name string `form:"name" validate:"required"`
|
Name string `form:"name" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TailscaleState string
|
|
||||||
|
|
||||||
const (
|
|
||||||
TailscaleNotInstall TailscaleState = "notInstall"
|
|
||||||
TailscaleNotRunning TailscaleState = "notRunning"
|
|
||||||
TailscaleNotLogin TailscaleState = "notLogin"
|
|
||||||
TailscaleStopped TailscaleState = "stopped"
|
|
||||||
TailscaleRunning TailscaleState = "running"
|
|
||||||
)
|
|
||||||
|
|
||||||
type GetTailscaleStatusRsp struct {
|
|
||||||
State TailscaleState `json:"state"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
IP string `json:"ip"`
|
|
||||||
Account string `json:"account"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoginTailscaleRsp struct {
|
|
||||||
Url string `json:"url"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetWifiRsp struct {
|
type GetWifiRsp struct {
|
||||||
Supported bool `json:"supported"`
|
Supported bool `json:"supported"`
|
||||||
Connected bool `json:"connected"`
|
ApMode bool `json:"apMode"`
|
||||||
|
Connected bool `json:"connected"`
|
||||||
|
Ssid string `json:"ssid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnectWifiReq struct {
|
||||||
|
Ssid string `validate:"required"`
|
||||||
|
Password string `valid:"required"`
|
||||||
}
|
}
|
||||||
|
|||||||
22
server/proto/tailscale.go
Normal file
22
server/proto/tailscale.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package proto
|
||||||
|
|
||||||
|
type TailscaleState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
TailscaleNotInstall TailscaleState = "notInstall"
|
||||||
|
TailscaleNotRunning TailscaleState = "notRunning"
|
||||||
|
TailscaleNotLogin TailscaleState = "notLogin"
|
||||||
|
TailscaleStopped TailscaleState = "stopped"
|
||||||
|
TailscaleRunning TailscaleState = "running"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetTailscaleStatusRsp struct {
|
||||||
|
State TailscaleState `json:"state"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
IP string `json:"ip"`
|
||||||
|
Account string `json:"account"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoginTailscaleRsp struct {
|
||||||
|
Url string `json:"url"`
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
func networkRouter(r *gin.Engine) {
|
func networkRouter(r *gin.Engine) {
|
||||||
service := network.NewService()
|
service := network.NewService()
|
||||||
|
|
||||||
r.POST("/api/network/wifi", service.ConnectWifi) // connect Wi-Fi
|
r.POST("/api/network/wifi", service.ConnectWifiNoAuth) // connect Wi-Fi without auth (only available in ap mode)
|
||||||
|
|
||||||
api := r.Group("/api").Use(middleware.CheckToken())
|
api := r.Group("/api").Use(middleware.CheckToken())
|
||||||
|
|
||||||
@@ -18,5 +18,8 @@ func networkRouter(r *gin.Engine) {
|
|||||||
api.GET("/network/wol/mac", service.GetMac) // get mac list
|
api.GET("/network/wol/mac", service.GetMac) // get mac list
|
||||||
api.DELETE("/network/wol/mac", service.DeleteMac) // delete mac
|
api.DELETE("/network/wol/mac", service.DeleteMac) // delete mac
|
||||||
api.POST("/network/wol/mac/name", service.SetMacName) // set mac name
|
api.POST("/network/wol/mac/name", service.SetMacName) // set mac name
|
||||||
api.GET("/network/wifi", service.GetWifi) // get Wi-Fi information
|
|
||||||
|
api.GET("/network/wifi", service.GetWifi) // get Wi-Fi information
|
||||||
|
api.POST("/network/wifi/connect", service.ConnectWifi) // connect Wi-Fi
|
||||||
|
api.POST("/network/wifi/disconnect", service.DisconnectWifi) // disconnect Wi-Fi
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,26 @@
|
|||||||
package network
|
package network
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"NanoKVM-Server/proto"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"NanoKVM-Server/proto"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
WiFiExistFile = "/etc/kvm/wifi_exist"
|
WiFiExistFile = "/etc/kvm/wifi_exist"
|
||||||
WiFiSSID = "/etc/kvm/wifi.ssid"
|
WiFiApModeFile = "/tmp/wifiap"
|
||||||
WiFiPasswd = "/etc/kvm/wifi.pass"
|
WiFiSSID = "/etc/kvm/wifi.ssid"
|
||||||
WiFiConnect = "/kvmapp/kvm/wifi_try_connect"
|
WiFiPasswd = "/etc/kvm/wifi.pass"
|
||||||
WiFiStateFile = "/kvmapp/kvm/wifi_state"
|
WiFiConnect = "/kvmapp/kvm/wifi_try_connect"
|
||||||
|
WiFiStateFile = "/kvmapp/kvm/wifi_state"
|
||||||
|
WiFiScript = "/etc/init.d/S30wifi"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Service) GetWifi(c *gin.Context) {
|
func (s *Service) GetWifi(c *gin.Context) {
|
||||||
@@ -22,25 +28,55 @@ func (s *Service) GetWifi(c *gin.Context) {
|
|||||||
|
|
||||||
data := &proto.GetWifiRsp{}
|
data := &proto.GetWifiRsp{}
|
||||||
|
|
||||||
_, err := os.Stat(WiFiExistFile)
|
data.Supported = isSupported()
|
||||||
if err != nil {
|
if !data.Supported {
|
||||||
rsp.OkRspWithData(c, data)
|
rsp.OkRspWithData(c, data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data.Supported = true
|
data.ApMode = isAPMode()
|
||||||
|
|
||||||
content, err := os.ReadFile(WiFiStateFile)
|
data.Connected = isConnected()
|
||||||
if err != nil {
|
if !data.Connected {
|
||||||
rsp.OkRspWithData(c, data)
|
rsp.OkRspWithData(c, data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
state := strings.ReplaceAll(string(content), "\n", "")
|
data.Ssid = getWiFiSsid()
|
||||||
data.Connected = state == "1"
|
if data.Ssid == "" {
|
||||||
|
data.Ssid = "Wi-Fi"
|
||||||
|
}
|
||||||
|
|
||||||
rsp.OkRspWithData(c, data)
|
rsp.OkRspWithData(c, data)
|
||||||
log.Debugf("get wifi state: %s", state)
|
log.Debugf("get wifi state: %+v", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ConnectWifiNoAuth(c *gin.Context) {
|
||||||
|
var req proto.ConnectWifiReq
|
||||||
|
var rsp proto.Response
|
||||||
|
|
||||||
|
// Check Wi-Fi configuration mode
|
||||||
|
if !isSupported() || !isAPMode() {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
rsp.ErrRsp(c, -1, "invalid mode")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := proto.ParseFormRequest(c, &req); err != nil {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
rsp.ErrRsp(c, -2, "invalid parameters")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := connect(req.Ssid, req.Password); err != nil {
|
||||||
|
rsp.ErrRsp(c, -3, "failed to connect wifi")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
|
||||||
|
rsp.OkRsp(c)
|
||||||
|
log.Debugf("set wifi ap mode successfully")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) ConnectWifi(c *gin.Context) {
|
func (s *Service) ConnectWifi(c *gin.Context) {
|
||||||
@@ -52,24 +88,97 @@ func (s *Service) ConnectWifi(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.WriteFile(WiFiSSID, []byte(req.Ssid), 0o644); err != nil {
|
if err := connect(req.Ssid, req.Password); err != nil {
|
||||||
log.Errorf("failed to save wifi ssid: %s", err)
|
rsp.ErrRsp(c, -2, "failed to connect wifi")
|
||||||
rsp.ErrRsp(c, -2, "failed to save wifi")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.WriteFile(WiFiPasswd, []byte(req.Password), 0o644); err != nil {
|
// Waiting for Wi-Fi connection
|
||||||
log.Errorf("failed to save wifi password: %s", err)
|
maxTries := 7
|
||||||
rsp.ErrRsp(c, -3, "failed to save wifi")
|
if isConnected() {
|
||||||
|
maxTries = 3
|
||||||
|
time.Sleep(12 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
for range maxTries {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
if isConnected() && getWiFiSsid() != "" {
|
||||||
|
rsp.OkRsp(c)
|
||||||
|
log.Debugf("set wifi successfully: %s", req.Ssid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rsp.ErrRsp(c, -3, "failed to get wifi status")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) DisconnectWifi(c *gin.Context) {
|
||||||
|
var rsp proto.Response
|
||||||
|
|
||||||
|
command := fmt.Sprintf("%s stop", WiFiScript)
|
||||||
|
cmd := exec.Command("sh", "-c", command)
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to disconnect wifi: %s", output)
|
||||||
|
rsp.ErrRsp(c, -1, "failed to stop wifi")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
|
||||||
|
_ = os.Remove(WiFiSSID)
|
||||||
|
_ = os.Remove(WiFiPasswd)
|
||||||
|
|
||||||
|
rsp.OkRsp(c)
|
||||||
|
log.Debugf("stop wifi successfully")
|
||||||
|
}
|
||||||
|
|
||||||
|
func connect(ssid string, password string) error {
|
||||||
|
if err := os.WriteFile(WiFiSSID, []byte(ssid), 0o644); err != nil {
|
||||||
|
log.Errorf("failed to save wifi ssid: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.WriteFile(WiFiPasswd, []byte(password), 0o644); err != nil {
|
||||||
|
log.Errorf("failed to save wifi password: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := os.WriteFile(WiFiConnect, nil, 0o644); err != nil {
|
if err := os.WriteFile(WiFiConnect, nil, 0o644); err != nil {
|
||||||
log.Errorf("failed to connect wifi: %s", err)
|
log.Errorf("failed to connect wifi: %s", err)
|
||||||
rsp.ErrRsp(c, -4, "failed to connect wifi")
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rsp.OkRsp(c)
|
return nil
|
||||||
log.Debugf("set wifi successfully: %s", req.Ssid)
|
}
|
||||||
|
|
||||||
|
func isSupported() bool {
|
||||||
|
_, err := os.Stat(WiFiExistFile)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAPMode() bool {
|
||||||
|
_, err := os.Stat(WiFiApModeFile)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isConnected() bool {
|
||||||
|
content, err := os.ReadFile(WiFiStateFile)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
state := strings.ReplaceAll(string(content), "\n", "")
|
||||||
|
return state == "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
func getWiFiSsid() string {
|
||||||
|
ssidByte, err := os.ReadFile(WiFiSSID)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.ReplaceAll(string(ssidByte), "\n", "")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
"i18next": "^23.16.4",
|
"i18next": "^23.16.4",
|
||||||
"jotai": "^2.10.1",
|
"jotai": "^2.10.1",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"lucide-react": "^0.469.0",
|
"lucide-react": "^0.562.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-draggable": "^4.4.6",
|
"react-draggable": "^4.4.6",
|
||||||
|
|||||||
10
web/pnpm-lock.yaml
generated
10
web/pnpm-lock.yaml
generated
@@ -42,8 +42,8 @@ importers:
|
|||||||
specifier: ^3.0.5
|
specifier: ^3.0.5
|
||||||
version: 3.0.5
|
version: 3.0.5
|
||||||
lucide-react:
|
lucide-react:
|
||||||
specifier: ^0.469.0
|
specifier: ^0.562.0
|
||||||
version: 0.469.0(react@18.3.1)
|
version: 0.562.0(react@18.3.1)
|
||||||
react:
|
react:
|
||||||
specifier: ^18.3.1
|
specifier: ^18.3.1
|
||||||
version: 18.3.1
|
version: 18.3.1
|
||||||
@@ -1982,8 +1982,8 @@ packages:
|
|||||||
lru-cache@5.1.1:
|
lru-cache@5.1.1:
|
||||||
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
|
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
|
||||||
|
|
||||||
lucide-react@0.469.0:
|
lucide-react@0.562.0:
|
||||||
resolution: {integrity: sha512-28vvUnnKQ/dBwiCQtwJw7QauYnE7yd2Cyp4tTTJpvglX4EMpbflcdBgrgToX2j71B3YvugK/NH3BGUk+E/p/Fw==}
|
resolution: {integrity: sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
@@ -5026,7 +5026,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
yallist: 3.1.1
|
yallist: 3.1.1
|
||||||
|
|
||||||
lucide-react@0.469.0(react@18.3.1):
|
lucide-react@0.562.0(react@18.3.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
|
|
||||||
|
|||||||
@@ -31,11 +31,25 @@ export function getWiFi() {
|
|||||||
return http.get('/api/network/wifi');
|
return http.get('/api/network/wifi');
|
||||||
}
|
}
|
||||||
|
|
||||||
// connect wifi
|
// connect wifi without auth (only available in wifi configuration mode)
|
||||||
export function connectWifi(ssid: string, password: string) {
|
export function connectWifiNoAuth(ssid: string, password: string) {
|
||||||
const data = {
|
const data = {
|
||||||
ssid,
|
ssid,
|
||||||
password
|
password
|
||||||
};
|
};
|
||||||
return http.post('/api/network/wifi', data);
|
return http.post('/api/network/wifi', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// connect wifi
|
||||||
|
export function connectWifi(ssid: string, password: string) {
|
||||||
|
const data = {
|
||||||
|
ssid,
|
||||||
|
password
|
||||||
|
};
|
||||||
|
return http.post('/api/network/wifi/connect', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// disconnect wifi
|
||||||
|
export function disconnectWifi() {
|
||||||
|
return http.post('/api/network/wifi/disconnect');
|
||||||
|
}
|
||||||
|
|||||||
@@ -41,8 +41,10 @@ const en = {
|
|||||||
wifi: {
|
wifi: {
|
||||||
title: 'Wi-Fi',
|
title: 'Wi-Fi',
|
||||||
description: 'Configure Wi-Fi for NanoKVM',
|
description: 'Configure Wi-Fi for NanoKVM',
|
||||||
success: 'Please check the network status of NanoKVM and visit the new IP address.',
|
success: 'Please go to the device to check the network status of NanoKVM.',
|
||||||
failed: 'Operation failed, please try again.',
|
failed: 'Operation failed, please try again.',
|
||||||
|
invalidMode:
|
||||||
|
'The current mode does not support network setup. Please go to your device and enable Wi-Fi configuration mode.',
|
||||||
confirmBtn: 'Ok',
|
confirmBtn: 'Ok',
|
||||||
finishBtn: 'Finished'
|
finishBtn: 'Finished'
|
||||||
},
|
},
|
||||||
@@ -186,9 +188,9 @@ const en = {
|
|||||||
input: 'Please enter a remote image URL',
|
input: 'Please enter a remote image URL',
|
||||||
ok: 'Ok',
|
ok: 'Ok',
|
||||||
disabled: '/data partition is RO, so we cannot download the image',
|
disabled: '/data partition is RO, so we cannot download the image',
|
||||||
uploadbox: "Drop file here or click to select",
|
uploadbox: 'Drop file here or click to select',
|
||||||
inputfile: "Please enter the image File",
|
inputfile: 'Please enter the image File',
|
||||||
NoISO: "No ISO"
|
NoISO: 'No ISO'
|
||||||
},
|
},
|
||||||
power: {
|
power: {
|
||||||
title: 'Power',
|
title: 'Power',
|
||||||
@@ -251,7 +253,17 @@ const en = {
|
|||||||
wifi: {
|
wifi: {
|
||||||
title: 'Wi-Fi',
|
title: 'Wi-Fi',
|
||||||
description: 'Configure Wi-Fi',
|
description: 'Configure Wi-Fi',
|
||||||
setBtn: 'Config'
|
apMode: 'AP mode is enabled, connect to Wi-Fi by scanning QR code',
|
||||||
|
connect: 'Join Wi-Fi',
|
||||||
|
connectDesc1: 'Please enter the network ssid and password',
|
||||||
|
connectDesc2: 'Please enter the password to join this network',
|
||||||
|
disconnect: 'Are you sure to disconnect the network?',
|
||||||
|
failed: 'Connection failed, please try again.',
|
||||||
|
ssid: 'Name',
|
||||||
|
password: 'Password',
|
||||||
|
joinBtn: 'Join',
|
||||||
|
confirmBtn: 'Ok',
|
||||||
|
cancelBtn: 'Cancel'
|
||||||
},
|
},
|
||||||
ssh: {
|
ssh: {
|
||||||
description: 'Enable SSH remote access',
|
description: 'Enable SSH remote access',
|
||||||
@@ -296,7 +308,7 @@ const en = {
|
|||||||
hidOnly: 'HID-Only Mode',
|
hidOnly: 'HID-Only Mode',
|
||||||
disk: 'Virtual Disk',
|
disk: 'Virtual Disk',
|
||||||
diskDesc: 'Mount SD card on the remote host',
|
diskDesc: 'Mount SD card on the remote host',
|
||||||
media: "Virtual Image",
|
media: 'Virtual Image',
|
||||||
mediaDesc: 'Attach virtual image device to the remote host',
|
mediaDesc: 'Attach virtual image device to the remote host',
|
||||||
network: 'Virtual Network',
|
network: 'Virtual Network',
|
||||||
networkDesc: 'Mount virtual network card on the remote host',
|
networkDesc: 'Mount virtual network card on the remote host',
|
||||||
@@ -371,9 +383,9 @@ const en = {
|
|||||||
updating: 'Update started. Please wait...',
|
updating: 'Update started. Please wait...',
|
||||||
confirm: 'Confirm',
|
confirm: 'Confirm',
|
||||||
cancel: 'Cancel',
|
cancel: 'Cancel',
|
||||||
inputfile: "Please enter the Update File",
|
inputfile: 'Please enter the Update File',
|
||||||
noupdatefile: "No update file",
|
noupdatefile: 'No update file',
|
||||||
uploadbox: "Drop file here or click to select",
|
uploadbox: 'Drop file here or click to select',
|
||||||
ok: 'Ok'
|
ok: 'Ok'
|
||||||
},
|
},
|
||||||
account: {
|
account: {
|
||||||
|
|||||||
@@ -40,8 +40,9 @@ const zh = {
|
|||||||
wifi: {
|
wifi: {
|
||||||
title: 'Wi-Fi',
|
title: 'Wi-Fi',
|
||||||
description: '配置 NanoKVM Wi-Fi 信息',
|
description: '配置 NanoKVM Wi-Fi 信息',
|
||||||
success: '请检查 NanoKVM 的网络状态,并访问新的 IP 地址。',
|
success: '请前往设备检查 NanoKVM 的网络状态。',
|
||||||
failed: '操作失败,请重试。',
|
failed: '操作失败,请重试。',
|
||||||
|
invalidMode: '当前模式不支持配置网络。请先前往设备启用 Wi-Fi 配置模式。',
|
||||||
confirmBtn: '确定',
|
confirmBtn: '确定',
|
||||||
finishBtn: '完成'
|
finishBtn: '完成'
|
||||||
},
|
},
|
||||||
@@ -222,7 +223,17 @@ const zh = {
|
|||||||
wifi: {
|
wifi: {
|
||||||
title: 'Wi-Fi',
|
title: 'Wi-Fi',
|
||||||
description: '配置 Wi-Fi 信息',
|
description: '配置 Wi-Fi 信息',
|
||||||
setBtn: '设置'
|
apMode: 'AP 模式已启用,该模式下仅支持扫描二维码配网',
|
||||||
|
connect: '连接 Wi-Fi',
|
||||||
|
connectDesc1: '请输入网络名称和密码',
|
||||||
|
connectDesc2: '请输入密码以连接此网络',
|
||||||
|
disconnect: '是否要断开该网络连接?',
|
||||||
|
failed: '连接失败,请重试',
|
||||||
|
ssid: '名称',
|
||||||
|
password: '密码',
|
||||||
|
joinBtn: '加入',
|
||||||
|
confirmBtn: '确定',
|
||||||
|
cancelBtn: '取消'
|
||||||
},
|
},
|
||||||
ssh: {
|
ssh: {
|
||||||
description: '启用 SSH 远程访问',
|
description: '启用 SSH 远程访问',
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Button } from 'antd';
|
import { LockOutlined, WifiOutlined } from '@ant-design/icons';
|
||||||
|
import { Button, Input, Modal, Switch } from 'antd';
|
||||||
|
import { WifiIcon, WifiPenIcon } from 'lucide-react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import * as api from '@/api/network.ts';
|
import * as api from '@/api/network.ts';
|
||||||
@@ -8,38 +10,198 @@ export const Wifi = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [isSupported, setIsSupported] = useState(false);
|
const [isSupported, setIsSupported] = useState(false);
|
||||||
|
const [isAPMode, setIsAPMode] = useState(false);
|
||||||
|
const [connectedWiFi, setConnectedWifi] = useState('');
|
||||||
|
|
||||||
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
const [ssid, setSsid] = useState('');
|
||||||
|
const [password, setPassword] = useState('');
|
||||||
|
const [status, setStatus] = useState<'' | 'connecting' | 'disconnecting'>('');
|
||||||
|
const [message, setMessage] = useState('');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api.getWiFi().then((rsp) => {
|
getWiFi();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
async function getWiFi() {
|
||||||
|
try {
|
||||||
|
const rsp = await api.getWiFi();
|
||||||
if (rsp.code !== 0) {
|
if (rsp.code !== 0) {
|
||||||
console.log(rsp.msg);
|
console.log(rsp.msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsSupported(rsp.data?.supported);
|
setIsSupported(!!rsp.data?.supported);
|
||||||
});
|
setIsAPMode(!!rsp.data?.apMode);
|
||||||
}, []);
|
|
||||||
|
|
||||||
function open() {
|
if (rsp.data?.connected && rsp.data?.ssid) {
|
||||||
window.open('/#/wifi', '_blank');
|
setConnectedWifi(rsp.data.ssid);
|
||||||
|
} else {
|
||||||
|
setConnectedWifi('');
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
/* empty */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function connect() {
|
||||||
|
setMessage('');
|
||||||
|
|
||||||
|
if (!ssid || !password) return;
|
||||||
|
|
||||||
|
if (status !== '') return;
|
||||||
|
setStatus('connecting');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const rsp = await api.connectWifi(ssid, password);
|
||||||
|
if (rsp.code !== 0) {
|
||||||
|
console.log(rsp.msg);
|
||||||
|
setMessage(t('settings.device.wifi.failed'));
|
||||||
|
getWiFi();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setConnectedWifi(ssid);
|
||||||
|
setIsModalOpen(false);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
} finally {
|
||||||
|
setStatus('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function disconnect(enable: boolean) {
|
||||||
|
if (enable || status !== '') return;
|
||||||
|
|
||||||
|
setStatus('disconnecting');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const rsp = await api.disconnectWifi();
|
||||||
|
if (rsp.code !== 0) {
|
||||||
|
console.log(rsp.msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setConnectedWifi('');
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
} finally {
|
||||||
|
setStatus('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openModal() {
|
||||||
|
setSsid('');
|
||||||
|
setPassword('');
|
||||||
|
setMessage('');
|
||||||
|
setIsModalOpen(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeModal() {
|
||||||
|
if (status !== '') return;
|
||||||
|
setIsModalOpen(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSupported) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAPMode) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span>{t('settings.device.wifi.title')}</span>
|
||||||
|
<span className="text-xs text-neutral-500">{t('settings.device.wifi.apMode')}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button shape="round" size="small" disabled>
|
||||||
|
<div className="flex items-center justify-center px-1.5">
|
||||||
|
<WifiIcon size={16} />
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isSupported && (
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex flex-col">
|
||||||
<div className="flex flex-col">
|
<span>{t('settings.device.wifi.title')}</span>
|
||||||
<span>{t('settings.device.wifi.title')}</span>
|
<span className="text-xs text-neutral-500">{t('settings.device.wifi.description')}</span>
|
||||||
<span className="text-xs text-neutral-500">
|
</div>
|
||||||
{t('settings.device.wifi.description')}
|
|
||||||
</span>
|
<Button
|
||||||
|
type={connectedWiFi ? 'primary' : 'default'}
|
||||||
|
shape="round"
|
||||||
|
size="small"
|
||||||
|
onClick={openModal}
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-center px-1.5">
|
||||||
|
<WifiIcon size={16} />
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
closable={false}
|
||||||
|
open={isModalOpen}
|
||||||
|
centered={true}
|
||||||
|
onOk={connect}
|
||||||
|
onCancel={closeModal}
|
||||||
|
okText={t('settings.device.wifi.joinBtn')}
|
||||||
|
cancelText={t('settings.device.wifi.cancelBtn')}
|
||||||
|
confirmLoading={status === 'connecting'}
|
||||||
|
>
|
||||||
|
{/* title */}
|
||||||
|
<div className="flex items-center space-x-5">
|
||||||
|
<div className="h-[64px] w-[64px]">
|
||||||
|
<WifiPenIcon size={64} className="text-blue-400" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button type="primary" size="small" onClick={open}>
|
{!connectedWiFi ? (
|
||||||
{t('settings.device.wifi.setBtn')}
|
<div className="flex flex-col">
|
||||||
</Button>
|
<span className="text-lg font-bold">{t('settings.device.wifi.connect')}</span>
|
||||||
|
<span className="text-xs text-neutral-400">
|
||||||
|
{t('settings.device.wifi.connectDesc1')}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<div className="flex w-[300px] justify-between rounded-lg bg-neutral-800">
|
||||||
|
<div className="flex w-full justify-between p-3">
|
||||||
|
<span>{connectedWiFi}</span>
|
||||||
|
<Switch
|
||||||
|
value={!!connectedWiFi}
|
||||||
|
loading={status === 'disconnecting'}
|
||||||
|
onChange={disconnect}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
{/* form */}
|
||||||
|
<div className="flex flex-col items-center space-y-3 py-6">
|
||||||
|
<Input
|
||||||
|
value={ssid}
|
||||||
|
style={{ width: '300px' }}
|
||||||
|
prefix={<WifiOutlined />}
|
||||||
|
placeholder={t('settings.device.wifi.ssid')}
|
||||||
|
onChange={(e) => setSsid(e.target.value)}
|
||||||
|
/>
|
||||||
|
<Input.Password
|
||||||
|
value={password}
|
||||||
|
style={{ width: '300px' }}
|
||||||
|
prefix={<LockOutlined />}
|
||||||
|
placeholder={t('settings.device.wifi.password')}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{!!message && <span className="text-sm text-red-500">{message}</span>}
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,32 +3,42 @@ import { CheckOutlined, LockOutlined, WifiOutlined } from '@ant-design/icons';
|
|||||||
import { Button, Form, Input } from 'antd';
|
import { Button, Form, Input } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { connectWifi } from '@/api/network.ts';
|
import * as api from '@/api/network.ts';
|
||||||
import { Head } from '@/components/head.tsx';
|
import { Head } from '@/components/head.tsx';
|
||||||
|
|
||||||
type State = '' | 'loading' | 'success' | 'failed';
|
type State = '' | 'loading' | 'success' | 'failed' | 'denied';
|
||||||
|
|
||||||
export const Wifi = () => {
|
export const Wifi = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [state, setState] = useState<State>('');
|
const [state, setState] = useState<State>('');
|
||||||
|
|
||||||
function connect(values: any) {
|
async function connect(values: any) {
|
||||||
if (state === 'loading' || state === 'success') return;
|
if (!values.ssid || !values.password) return;
|
||||||
|
|
||||||
const ssid = values.ssid;
|
|
||||||
const password = values.password;
|
|
||||||
if (!ssid || !password) return;
|
|
||||||
|
|
||||||
|
if (state === 'loading') return;
|
||||||
setState('loading');
|
setState('loading');
|
||||||
|
|
||||||
connectWifi(ssid, password)
|
try {
|
||||||
.then((rsp) => {
|
const rsp = await api.connectWifiNoAuth(values.ssid, values.password);
|
||||||
setState(rsp.code === 0 ? 'success' : 'failed');
|
|
||||||
})
|
switch (rsp?.code) {
|
||||||
.catch(() => {
|
case 0:
|
||||||
setState('failed');
|
setState('success');
|
||||||
});
|
return;
|
||||||
|
case -1:
|
||||||
|
setState('denied');
|
||||||
|
return;
|
||||||
|
case -2:
|
||||||
|
case -3:
|
||||||
|
setState('failed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
setState('success');
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -74,12 +84,17 @@ export const Wifi = () => {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
<div className="flex h-6 justify-center px-10">
|
<div className="flex max-w-[500px] justify-center px-5 pt-3 md:px-10">
|
||||||
{state === 'success' && (
|
{state === 'success' && (
|
||||||
<span className="text-sm text-green-500">{t('wifi.success')}</span>
|
<span className="text-sm text-green-500">{t('wifi.success')}</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{state === 'failed' && <span className="text-sm text-red-500">{t('wifi.failed')} </span>}
|
{state === 'failed' && <span className="text-sm text-red-500">{t('wifi.failed')} </span>}
|
||||||
|
{state === 'denied' && (
|
||||||
|
<div className="flex flex-col items-center space-y-5">
|
||||||
|
<span className="text-sm text-red-500">{t('wifi.invalidMode')} </span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user