Compare commits

...

8 Commits

Author SHA1 Message Date
Daniel Collins 833f33fdd6
Merge 5d18462a51 into bde0a086ab 2025-07-03 12:27:29 -05:00
Siyuan Miao bde0a086ab chore: bump to 0.4.7 2025-07-03 19:03:46 +02:00
Aveline 9c9335da31
chore: typo 'supression' should be 'suppression' (#671) 2025-07-03 17:28:00 +02:00
dependabot[bot] 090e0b4b47
build(deps): bump actions/setup-go from 4.2.1 to 5.5.0 (#666)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 4.2.1 to 5.5.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v4.2.1...v5.5.0)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: 5.5.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-03 17:21:11 +02:00
dependabot[bot] 48a7a638a3
build(deps): bump github.com/pion/webrtc/v4 from 4.1.2 to 4.1.3 (#667)
Bumps [github.com/pion/webrtc/v4](https://github.com/pion/webrtc) from 4.1.2 to 4.1.3.
- [Release notes](https://github.com/pion/webrtc/releases)
- [Changelog](https://github.com/pion/webrtc/blob/master/.goreleaser.yml)
- [Commits](https://github.com/pion/webrtc/compare/v4.1.2...v4.1.3)

---
updated-dependencies:
- dependency-name: github.com/pion/webrtc/v4
  dependency-version: 4.1.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-03 17:21:04 +02:00
dependabot[bot] e4f6a713a5
build(deps): bump github.com/Masterminds/semver/v3 from 3.3.1 to 3.4.0 (#668)
Bumps [github.com/Masterminds/semver/v3](https://github.com/Masterminds/semver) from 3.3.1 to 3.4.0.
- [Release notes](https://github.com/Masterminds/semver/releases)
- [Changelog](https://github.com/Masterminds/semver/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Masterminds/semver/compare/v3.3.1...v3.4.0)

---
updated-dependencies:
- dependency-name: github.com/Masterminds/semver/v3
  dependency-version: 3.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-03 17:19:27 +02:00
Aveline 9fcf74b398
fix(display): reset display state after native binary is restarted (#654)
* fix(usbgadget): add lock for logWithSupression

* fix(display): reset display state after native binary is restarted
2025-07-03 17:18:09 +02:00
Daniel Collins 5d18462a51 Add -i/--install option to dev_deploy.sh
Running `dev_deploy.sh -i` will build the app in release mode and
install it to the device for longer term development/testing or just
running a custom variant of the app.
2025-05-28 20:55:07 +01:00
13 changed files with 87 additions and 43 deletions

View File

@ -23,7 +23,7 @@ jobs:
cache: "npm"
cache-dependency-path: "**/package-lock.json"
- name: Set up Golang
uses: actions/setup-go@v5
uses: actions/setup-go@v5.5.0
with:
go-version: "1.24.4"
- name: Build frontend

View File

@ -24,7 +24,7 @@ jobs:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Install Go
uses: actions/setup-go@19bb51245e9c80abacb2e91cc42b33fa478b8639 # v4.2.1
uses: actions/setup-go@fa96338abe5531f6e34c5cc0bbe28c1a533d5505 # v4.2.1
with:
go-version: 1.24.4
- name: Create empty resource directory

View File

@ -104,7 +104,7 @@ jobs:
EOF
ssh jkci "cat /tmp/device-tests.json" > device-tests.json
- name: Set up Golang
uses: actions/setup-go@v5
uses: actions/setup-go@v5.5.0
with:
go-version: "1.24.4"
- name: Golang Test Report

View File

@ -2,8 +2,8 @@ BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
BUILDDATE ?= $(shell date -u +%FT%T%z)
BUILDTS ?= $(shell date -u +%s)
REVISION ?= $(shell git rev-parse HEAD)
VERSION_DEV ?= 0.4.6-dev$(shell date +%Y%m%d%H%M)
VERSION ?= 0.4.5
VERSION_DEV ?= 0.4.7-dev$(shell date +%Y%m%d%H%M)
VERSION ?= 0.4.6
PROMETHEUS_TAG := github.com/prometheus/common/version
KVM_PKG_NAME := github.com/jetkvm/kvm

View File

@ -28,6 +28,7 @@ show_help() {
echo " --run-go-tests Run go tests"
echo " --run-go-tests-only Run go tests and exit"
echo " --skip-ui-build Skip frontend/UI build"
echo " -i, --install Build for release and install the app"
echo " --help Display this help message"
echo
echo "Example:"
@ -43,6 +44,7 @@ RESET_USB_HID_DEVICE=false
LOG_TRACE_SCOPES="${LOG_TRACE_SCOPES:-jetkvm,cloud,websocket,native,jsonrpc}"
RUN_GO_TESTS=false
RUN_GO_TESTS_ONLY=false
INSTALL_APP=false
# Parse command line arguments
while [[ $# -gt 0 ]]; do
@ -72,6 +74,10 @@ while [[ $# -gt 0 ]]; do
RUN_GO_TESTS=true
shift
;;
-i|--install)
INSTALL_APP=true
shift
;;
--help)
show_help
exit 0
@ -139,25 +145,36 @@ EOF
fi
fi
msg_info "▶ Building go binary"
make build_dev
# Kill any existing instances of the application
ssh "${REMOTE_USER}@${REMOTE_HOST}" "killall jetkvm_app_debug || true"
# Copy the binary to the remote host
ssh "${REMOTE_USER}@${REMOTE_HOST}" "cat > ${REMOTE_PATH}/jetkvm_app_debug" < bin/jetkvm_app
if [ "$RESET_USB_HID_DEVICE" = true ]; then
msg_info "▶ Resetting USB HID device"
msg_warn "The option has been deprecated and will be removed in a future version, as JetKVM will now reset USB gadget configuration when needed"
# Remove the old USB gadget configuration
ssh "${REMOTE_USER}@${REMOTE_HOST}" "rm -rf /sys/kernel/config/usb_gadget/jetkvm/configs/c.1/hid.usb*"
ssh "${REMOTE_USER}@${REMOTE_HOST}" "ls /sys/class/udc > /sys/kernel/config/usb_gadget/jetkvm/UDC"
fi
# Deploy and run the application on the remote host
ssh "${REMOTE_USER}@${REMOTE_HOST}" ash << EOF
if [ "$INSTALL_APP" = true ]
then
msg_info "▶ Building release binary"
make build_release
# Copy the binary to the remote host as if we were the OTA updater.
ssh "${REMOTE_USER}@${REMOTE_HOST}" "cat > /userdata/jetkvm/jetkvm_app.update" < bin/jetkvm_app
# Reboot the device, the new app will be deployed by the startup process.
ssh "${REMOTE_USER}@${REMOTE_HOST}" "reboot"
else
msg_info "▶ Building development binary"
make build_dev
# Kill any existing instances of the application
ssh "${REMOTE_USER}@${REMOTE_HOST}" "killall jetkvm_app_debug || true"
# Copy the binary to the remote host
ssh "${REMOTE_USER}@${REMOTE_HOST}" "cat > ${REMOTE_PATH}/jetkvm_app_debug" < bin/jetkvm_app
if [ "$RESET_USB_HID_DEVICE" = true ]; then
msg_info "▶ Resetting USB HID device"
msg_warn "The option has been deprecated and will be removed in a future version, as JetKVM will now reset USB gadget configuration when needed"
# Remove the old USB gadget configuration
ssh "${REMOTE_USER}@${REMOTE_HOST}" "rm -rf /sys/kernel/config/usb_gadget/jetkvm/configs/c.1/hid.usb*"
ssh "${REMOTE_USER}@${REMOTE_HOST}" "ls /sys/class/udc > /sys/kernel/config/usb_gadget/jetkvm/UDC"
fi
# Deploy and run the application on the remote host
ssh "${REMOTE_USER}@${REMOTE_HOST}" ash << EOF
set -e
# Set the library path to include the directory where librockit.so is located
@ -176,5 +193,6 @@ chmod +x jetkvm_app_debug
# Run the application in the background
PION_LOG_TRACE=${LOG_TRACE_SCOPES} GODEBUG=netdns=1 ./jetkvm_app_debug
EOF
fi
echo "Deployment complete."
echo "Deployment complete."

View File

@ -9,9 +9,14 @@ import (
"time"
)
var currentScreen = "ui_Boot_Screen"
var backlightState = 0 // 0 - NORMAL, 1 - DIMMED, 2 - OFF
var (
currentScreen = "ui_Boot_Screen"
displayedTexts = make(map[string]string)
screenStateLock = sync.Mutex{}
)
var (
dimTicker *time.Ticker
offTicker *time.Ticker
@ -22,6 +27,8 @@ const (
backlightControlClass string = "/sys/class/backlight/backlight/brightness"
)
// do not call this function directly, use switchToScreenIfDifferent instead
// this function is not thread safe
func switchToScreen(screen string) {
_, err := CallCtrlAction("lv_scr_load", map[string]interface{}{"obj": screen})
if err != nil {
@ -31,8 +38,6 @@ func switchToScreen(screen string) {
currentScreen = screen
}
var displayedTexts = make(map[string]string)
func lvObjSetState(objName string, state string) (*CtrlResponse, error) {
return CallCtrlAction("lv_obj_set_state", map[string]interface{}{"obj": objName, "state": state})
}
@ -78,6 +83,9 @@ func lvDispSetRotation(rotation string) (*CtrlResponse, error) {
}
func updateLabelIfChanged(objName string, newText string) {
screenStateLock.Lock()
defer screenStateLock.Unlock()
if newText != "" && newText != displayedTexts[objName] {
_, _ = lvLabelSetText(objName, newText)
displayedTexts[objName] = newText
@ -85,12 +93,23 @@ func updateLabelIfChanged(objName string, newText string) {
}
func switchToScreenIfDifferent(screenName string) {
screenStateLock.Lock()
defer screenStateLock.Unlock()
if currentScreen != screenName {
displayLogger.Info().Str("from", currentScreen).Str("to", screenName).Msg("switching screen")
switchToScreen(screenName)
}
}
func clearDisplayState() {
screenStateLock.Lock()
defer screenStateLock.Unlock()
displayedTexts = make(map[string]string)
currentScreen = "ui_Boot_Screen"
}
var (
cloudBlinkLock sync.Mutex = sync.Mutex{}
cloudBlinkStopped bool

6
go.mod
View File

@ -3,7 +3,7 @@ module github.com/jetkvm/kvm
go 1.24.4
require (
github.com/Masterminds/semver/v3 v3.3.1
github.com/Masterminds/semver/v3 v3.4.0
github.com/beevik/ntp v1.4.3
github.com/coder/websocket v1.8.13
github.com/coreos/go-oidc/v3 v3.14.1
@ -17,7 +17,7 @@ require (
github.com/hanwen/go-fuse/v2 v2.8.0
github.com/pion/logging v0.2.4
github.com/pion/mdns/v2 v2.0.7
github.com/pion/webrtc/v4 v4.1.2
github.com/pion/webrtc/v4 v4.1.3
github.com/pojntfx/go-nbd v0.3.2
github.com/prometheus/client_golang v1.22.0
github.com/prometheus/common v0.65.0
@ -66,7 +66,7 @@ require (
github.com/pion/interceptor v0.1.40 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.15 // indirect
github.com/pion/rtp v1.8.19 // indirect
github.com/pion/rtp v1.8.20 // indirect
github.com/pion/sctp v1.8.39 // indirect
github.com/pion/sdp/v3 v3.0.14 // indirect
github.com/pion/srtp/v3 v3.0.6 // indirect

12
go.sum
View File

@ -1,5 +1,5 @@
github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/beevik/ntp v1.4.3 h1:PlbTvE5NNy4QHmA4Mg57n7mcFTmr1W1j3gcK7L1lqho=
github.com/beevik/ntp v1.4.3/go.mod h1:Unr8Zg+2dRn7d8bHFuehIMSvvUYssHMxW3Q5Nx4RW5Q=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@ -117,8 +117,8 @@ github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo=
github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0=
github.com/pion/rtp v1.8.19 h1:jhdO/3XhL/aKm/wARFVmvTfq0lC/CvN1xwYKmduly3c=
github.com/pion/rtp v1.8.19/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk=
github.com/pion/rtp v1.8.20 h1:8zcyqohadZE8FCBeGdyEvHiclPIezcwRQH9zfapFyYI=
github.com/pion/rtp v1.8.20/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk=
github.com/pion/sctp v1.8.39 h1:PJma40vRHa3UTO3C4MyeJDQ+KIobVYRZQZ0Nt7SjQnE=
github.com/pion/sctp v1.8.39/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE=
github.com/pion/sdp/v3 v3.0.14 h1:1h7gBr9FhOWH5GjWWY5lcw/U85MtdcibTyt/o6RxRUI=
@ -131,8 +131,8 @@ github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1
github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo=
github.com/pion/turn/v4 v4.0.2 h1:ZqgQ3+MjP32ug30xAbD6Mn+/K4Sxi3SdNOTFf+7mpps=
github.com/pion/turn/v4 v4.0.2/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7IToA1zs=
github.com/pion/webrtc/v4 v4.1.2 h1:mpuUo/EJ1zMNKGE79fAdYNFZBX790KE7kQQpLMjjR54=
github.com/pion/webrtc/v4 v4.1.2/go.mod h1:xsCXiNAmMEjIdFxAYU0MbB3RwRieJsegSB2JZsGN+8U=
github.com/pion/webrtc/v4 v4.1.3 h1:YZ67Boj9X/hk190jJZ8+HFGQ6DqSZ/fYP3sLAZv7c3c=
github.com/pion/webrtc/v4 v4.1.3/go.mod h1:rsq+zQ82ryfR9vbb0L1umPJ6Ogq7zm8mcn9fcGnxomM=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=

View File

@ -143,7 +143,7 @@ func (u *UsbGadget) listenKeyboardEvents() {
default:
l.Trace().Msg("reading from keyboard")
if u.keyboardHidFile == nil {
u.logWithSupression("keyboardHidFileNil", 100, &l, nil, "keyboardHidFile is nil")
u.logWithSuppression("keyboardHidFileNil", 100, &l, nil, "keyboardHidFile is nil")
// show the error every 100 times to avoid spamming the logs
time.Sleep(time.Second)
continue
@ -153,7 +153,7 @@ func (u *UsbGadget) listenKeyboardEvents() {
n, err := u.keyboardHidFile.Read(buf)
if err != nil {
u.logWithSupression("keyboardHidFileRead", 100, &l, err, "failed to read")
u.logWithSuppression("keyboardHidFileRead", 100, &l, err, "failed to read")
continue
}
u.resetLogSuppressionCounter("keyboardHidFileRead")
@ -201,7 +201,7 @@ func (u *UsbGadget) keyboardWriteHidFile(data []byte) error {
_, err := u.keyboardHidFile.Write(data)
if err != nil {
u.logWithSupression("keyboardWriteHidFile", 100, u.log, err, "failed to write to hidg0")
u.logWithSuppression("keyboardWriteHidFile", 100, u.log, err, "failed to write to hidg0")
u.keyboardHidFile.Close()
u.keyboardHidFile = nil
return err

View File

@ -75,7 +75,7 @@ func (u *UsbGadget) absMouseWriteHidFile(data []byte) error {
_, err := u.absMouseHidFile.Write(data)
if err != nil {
u.logWithSupression("absMouseWriteHidFile", 100, u.log, err, "failed to write to hidg1")
u.logWithSuppression("absMouseWriteHidFile", 100, u.log, err, "failed to write to hidg1")
u.absMouseHidFile.Close()
u.absMouseHidFile = nil
return err

View File

@ -65,7 +65,7 @@ func (u *UsbGadget) relMouseWriteHidFile(data []byte) error {
_, err := u.relMouseHidFile.Write(data)
if err != nil {
u.logWithSupression("relMouseWriteHidFile", 100, u.log, err, "failed to write to hidg2")
u.logWithSuppression("relMouseWriteHidFile", 100, u.log, err, "failed to write to hidg2")
u.relMouseHidFile.Close()
u.relMouseHidFile = nil
return err

View File

@ -81,7 +81,7 @@ func compareFileContent(oldContent []byte, newContent []byte, looserMatch bool)
return false
}
func (u *UsbGadget) logWithSupression(counterName string, every int, logger *zerolog.Logger, err error, msg string, args ...interface{}) {
func (u *UsbGadget) logWithSuppression(counterName string, every int, logger *zerolog.Logger, err error, msg string, args ...interface{}) {
u.logSuppressionLock.Lock()
defer u.logSuppressionLock.Unlock()

View File

@ -272,6 +272,13 @@ func restartNativeBinary(binaryPath string) error {
nativeLogger.Warn().Err(err).Msg("failed to restart binary")
}
nativeCmd = cmd
// reset the display state
time.Sleep(1 * time.Second)
clearDisplayState()
updateStaticContents()
requestDisplayUpdate(true)
return err
}