mirror of
https://github.com/sipeed/NanoKVM.git
synced 2026-09-11 00:22:56 -05:00
feat: add internal USB recovery and initialize picoclaw token
This commit is contained in:
@@ -25,9 +25,13 @@ func GetPicoclawInternalToken() (string, error) {
|
||||
return picoclawInternalToken.value, nil
|
||||
}
|
||||
|
||||
if token, err := readPicoclawInternalToken(); err == nil && token != "" {
|
||||
picoclawInternalToken.value = token
|
||||
return token, nil
|
||||
if token, err := readPicoclawInternalToken(); err == nil {
|
||||
if token != "" {
|
||||
picoclawInternalToken.value = token
|
||||
return token, nil
|
||||
}
|
||||
} else if !os.IsNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
token := generateRandomSecretKey()
|
||||
@@ -42,6 +46,11 @@ func GetPicoclawInternalToken() (string, error) {
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func EnsurePicoclawInternalToken() error {
|
||||
_, err := GetPicoclawInternalToken()
|
||||
return err
|
||||
}
|
||||
|
||||
func readPicoclawInternalToken() (string, error) {
|
||||
data, err := os.ReadFile(picoclawInternalTokenFile)
|
||||
if err != nil {
|
||||
|
||||
@@ -28,6 +28,10 @@ func main() {
|
||||
}
|
||||
|
||||
func initialize() {
|
||||
if err := config.EnsurePicoclawInternalToken(); err != nil {
|
||||
log.Fatalf("failed to initialize picoclaw internal token: %v", err)
|
||||
}
|
||||
|
||||
logger.Init()
|
||||
|
||||
// init screen parameters
|
||||
@@ -82,7 +86,7 @@ func run() {
|
||||
httpAddr,
|
||||
httpsAddr,
|
||||
r,
|
||||
router.PicoclawLoopbackHTTPAllowedPaths()...,
|
||||
router.LoopbackHTTPAllowedPaths()...,
|
||||
); err != nil {
|
||||
panic("start http server failed")
|
||||
}
|
||||
|
||||
@@ -7,9 +7,16 @@ import (
|
||||
"NanoKVM-Server/service/hid"
|
||||
)
|
||||
|
||||
const internalUSBRecoverPath = "/api/internal/usb/recover"
|
||||
|
||||
func HIDLoopbackHTTPAllowedPaths() []string {
|
||||
return []string{internalUSBRecoverPath}
|
||||
}
|
||||
|
||||
func hidRouter(r *gin.Engine) {
|
||||
service := hid.NewService()
|
||||
api := r.Group("/api").Use(middleware.CheckToken())
|
||||
localAPI := r.Group("/api/internal").Use(middleware.CheckLoopbackInternalToken())
|
||||
|
||||
api.POST("/hid/paste", service.Paste) // paste
|
||||
|
||||
@@ -23,4 +30,6 @@ func hidRouter(r *gin.Engine) {
|
||||
api.GET("/hid/mode", service.GetHidMode) // get hid mode
|
||||
api.POST("/hid/mode", service.SetHidMode) // set hid mode
|
||||
api.POST("/hid/reset", service.ResetHid) // reset hid
|
||||
|
||||
localAPI.POST("/usb/recover", service.RecoverUSB)
|
||||
}
|
||||
|
||||
@@ -41,3 +41,9 @@ func server(r *gin.Engine) {
|
||||
downloadRouter(r)
|
||||
extensionsRouter(r)
|
||||
}
|
||||
|
||||
func LoopbackHTTPAllowedPaths() []string {
|
||||
paths := PicoclawLoopbackHTTPAllowedPaths()
|
||||
paths = append(paths, HIDLoopbackHTTPAllowedPaths()...)
|
||||
return paths
|
||||
}
|
||||
|
||||
@@ -91,6 +91,30 @@ func (s *Service) SetHidMode(c *gin.Context) {
|
||||
func (s *Service) ResetHid(c *gin.Context) {
|
||||
var rsp proto.Response
|
||||
|
||||
if err := ResetUSBPHY(); err != nil {
|
||||
log.Errorf("failed to reset hid: %v", err)
|
||||
rsp.ErrRsp(c, -1, "failed to reset hid")
|
||||
return
|
||||
}
|
||||
|
||||
rsp.OkRsp(c)
|
||||
log.Debugf("reset hid success")
|
||||
}
|
||||
|
||||
func (s *Service) RecoverUSB(c *gin.Context) {
|
||||
var rsp proto.Response
|
||||
|
||||
if err := ResetUSBPHY(); err != nil {
|
||||
log.Errorf("failed to recover usb: %v", err)
|
||||
rsp.ErrRsp(c, -1, "failed to recover usb")
|
||||
return
|
||||
}
|
||||
|
||||
rsp.OkRsp(c)
|
||||
log.Debugf("recover usb success")
|
||||
}
|
||||
|
||||
func ResetUSBPHY() error {
|
||||
h := GetHid()
|
||||
h.Lock()
|
||||
h.CloseNoLock()
|
||||
@@ -102,13 +126,10 @@ func (s *Service) ResetHid(c *gin.Context) {
|
||||
command := fmt.Sprintf("%s restart_phy", USBDevScript)
|
||||
err := exec.Command("sh", "-c", command).Run()
|
||||
if err != nil {
|
||||
log.Errorf("failed to reset hid: %v", err)
|
||||
rsp.ErrRsp(c, -1, "failed to reset hid")
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
rsp.OkRsp(c)
|
||||
log.Debugf("reset hid success")
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyModeFile(srcScript string) error {
|
||||
|
||||
@@ -5,6 +5,8 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
import * as api from '@/api/vm.ts';
|
||||
|
||||
const DEFAULT_POWER_LONG_DURATION_SECONDS = 12;
|
||||
|
||||
type PowerLongProps = {
|
||||
showConfirm: boolean;
|
||||
isLoading: boolean;
|
||||
@@ -14,7 +16,7 @@ type PowerLongProps = {
|
||||
export const PowerLong = ({ showConfirm, isLoading, setIsLoading }: PowerLongProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [duration, setDuration] = useState(8);
|
||||
const [duration, setDuration] = useState(DEFAULT_POWER_LONG_DURATION_SECONDS);
|
||||
|
||||
function power() {
|
||||
if (isLoading) return;
|
||||
@@ -55,7 +57,7 @@ export const PowerLong = ({ showConfirm, isLoading, setIsLoading }: PowerLongPro
|
||||
|
||||
<div className="px-3">
|
||||
<Slider
|
||||
defaultValue={8}
|
||||
defaultValue={DEFAULT_POWER_LONG_DURATION_SECONDS}
|
||||
min={1}
|
||||
max={30}
|
||||
tooltip={{ placement: 'bottom' }}
|
||||
|
||||
Reference in New Issue
Block a user