Skip to content

Commit 15d2766

Browse files
committed
Update App version to 0.0.2
1 parent 8fbd6bc commit 15d2766

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+3346
-251
lines changed

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,9 @@ static/*
33
.idea
44
.DS_Store
55
.vscode
6+
package-lock.json
7+
package.json
8+
node_modules/
69

7-
device-tests.tar.gz
10+
11+
device-tests.tar.gz

.golangci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ linters:
55
- misspell
66
- whitespace
77
- gochecknoinits
8+
disable:
9+
- unused
810
settings:
911
forbidigo:
1012
forbid:

.vscode/settings.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
22
BUILDDATE ?= $(shell date -u +%FT%T%z)
33
BUILDTS ?= $(shell date -u +%s)
44
REVISION ?= $(shell git rev-parse HEAD)
5-
VERSION_DEV ?= 0.0.1-dev
6-
VERSION ?= 0.0.1
5+
VERSION_DEV ?= 0.0.2-dev
6+
VERSION ?= 0.0.2
77

88
PROMETHEUS_TAG := github.com/prometheus/common/version
99
KVM_PKG_NAME := kvm

audio.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ func StartNtpAudioServer(handleClient func(net.Conn)) {
9999
}
100100

101101
func StopNtpAudioServer() {
102-
CallAudioCtrlAction("set_audio_enable", map[string]interface{}{"audio_enable": false})
102+
_, err := CallAudioCtrlAction("set_audio_enable", map[string]interface{}{"audio_enable": false})
103+
if err != nil {
104+
audioLogger.Error().Err(err).Msg("failed to set audio enable")
105+
}
103106

104107
if audioListener != nil {
105108
audioListener.Close()
@@ -138,7 +141,7 @@ func handleAudioClient(conn net.Conn) {
138141
}
139142

140143
timestamp += timestampStep
141-
packet.Header.Timestamp = timestamp
144+
packet.Timestamp = timestamp
142145
buf, err := packet.Marshal()
143146
if err != nil {
144147
audioLogger.Warn().Err(err).Msg("error marshalling packet")

cloud.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,7 @@ func handleSessionRequest(
118118
source string,
119119
scopedLogger *zerolog.Logger,
120120
) error {
121-
var sourceType string
122-
sourceType = "local"
121+
var sourceType = "local"
123122

124123
timer := prometheus.NewTimer(prometheus.ObserverFunc(func(v float64) {
125124
metricConnectionLastSessionRequestDuration.WithLabelValues(sourceType, source).Set(v)

config.go

Lines changed: 187 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
package kvm
22

33
import (
4+
"bufio"
45
"encoding/json"
56
"fmt"
7+
"io"
68
"os"
9+
"os/exec"
10+
"path/filepath"
11+
"strings"
712
"sync"
813

914
"kvm/internal/logging"
@@ -75,8 +80,7 @@ func (m *KeyboardMacro) Validate() error {
7580
}
7681

7782
type Config struct {
78-
CloudToken string `json:"cloud_token"`
79-
GoogleIdentity string `json:"google_identity"`
83+
STUN string `json:"stun"`
8084
JigglerEnabled bool `json:"jiggler_enabled"`
8185
AutoUpdateEnabled bool `json:"auto_update_enabled"`
8286
IncludePreRelease bool `json:"include_pre_release"`
@@ -102,6 +106,8 @@ type Config struct {
102106
TailScaleXEdge bool `json:"tailscale_xedge"`
103107
ZeroTierNetworkID string `json:"zerotier_network_id"`
104108
ZeroTierAutoStart bool `json:"zerotier_autostart"`
109+
FrpcAutoStart bool `json:"frpc_autostart"`
110+
FrpcToml string `json:"frpc_toml"`
105111
IO0Status bool `json:"io0_status"`
106112
IO1Status bool `json:"io1_status"`
107113
AudioMode string `json:"audio_mode"`
@@ -111,8 +117,10 @@ type Config struct {
111117
}
112118

113119
const configPath = "/userdata/kvm_config.json"
120+
const sdConfigPath = "/mnt/sdcard/kvm_config.json"
114121

115122
var defaultConfig = &Config{
123+
STUN: "stun:stun.l.google.com:19302",
116124
AutoUpdateEnabled: false, // Set a default value
117125
ActiveExtension: "",
118126
KeyboardMacros: []KeyboardMacro{},
@@ -135,13 +143,15 @@ var defaultConfig = &Config{
135143
RelativeMouse: true,
136144
Keyboard: true,
137145
MassStorage: true,
138-
Audio: true,
146+
Audio: false, //At any given time, only one of Audio and Mtp can be set to true
147+
Mtp: false,
139148
},
140149
NetworkConfig: &network.NetworkConfig{},
141150
DefaultLogLevel: "INFO",
142151
ZeroTierAutoStart: false,
143152
TailScaleAutoStart: false,
144153
TailScaleXEdge: false,
154+
FrpcAutoStart: false,
145155
IO0Status: true,
146156
IO1Status: true,
147157
AudioMode: "disabled",
@@ -165,6 +175,14 @@ func LoadConfig() {
165175

166176
// load the default config
167177
config = defaultConfig
178+
if config.UsbConfig.SerialNumber == "" {
179+
serialNumber, err := extractSerialNumber()
180+
if err != nil {
181+
logger.Warn().Err(err).Msg("failed to extract serial number")
182+
} else {
183+
config.UsbConfig.SerialNumber = serialNumber
184+
}
185+
}
168186

169187
file, err := os.Open(configPath)
170188
if err != nil {
@@ -177,6 +195,10 @@ func LoadConfig() {
177195
loadedConfig := *defaultConfig
178196
if err := json.NewDecoder(file).Decode(&loadedConfig); err != nil {
179197
logger.Warn().Err(err).Msg("config file JSON parsing failed")
198+
os.Remove(configPath)
199+
if _, err := os.Stat(sdConfigPath); err == nil {
200+
os.Remove(sdConfigPath)
201+
}
180202
return
181203
}
182204

@@ -200,6 +222,74 @@ func LoadConfig() {
200222
logger.Info().Str("path", configPath).Msg("config loaded")
201223
}
202224

225+
func copyFile(src, dst string) error {
226+
in, err := os.Open(src)
227+
if err != nil {
228+
return err
229+
}
230+
defer in.Close()
231+
232+
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
233+
return err
234+
}
235+
236+
out, err := os.Create(dst)
237+
if err != nil {
238+
return err
239+
}
240+
defer func() {
241+
if cerr := out.Close(); cerr != nil && err == nil {
242+
err = cerr
243+
}
244+
}()
245+
246+
if _, err := io.Copy(out, in); err != nil {
247+
return err
248+
}
249+
250+
if err := out.Sync(); err != nil {
251+
return err
252+
}
253+
254+
return nil
255+
}
256+
257+
func SyncConfigSD(isUpdate bool) {
258+
resp, err := rpcGetSDMountStatus()
259+
if err != nil {
260+
logger.Error().Err(err).Msg("failed to get sd mount status")
261+
return
262+
}
263+
264+
if resp.Status == SDMountOK {
265+
if _, err := os.Stat(configPath); err != nil {
266+
if err := SaveConfig(); err != nil {
267+
logger.Error().Err(err).Msg("failed to create kvm_config.json")
268+
return
269+
}
270+
}
271+
272+
if isUpdate {
273+
if _, err := os.Stat(sdConfigPath); err == nil {
274+
if err := copyFile(sdConfigPath, configPath); err != nil {
275+
logger.Error().Err(err).Msg("failed to copy kvm_config.json from sdcard to userdata")
276+
return
277+
}
278+
} else {
279+
if err := copyFile(configPath, sdConfigPath); err != nil {
280+
logger.Error().Err(err).Msg("failed to copy kvm_config.json from userdata to sdcard")
281+
return
282+
}
283+
}
284+
} else {
285+
if err := copyFile(configPath, sdConfigPath); err != nil {
286+
logger.Error().Err(err).Msg("failed to copy kvm_config.json from userdata to sdcard")
287+
return
288+
}
289+
}
290+
}
291+
}
292+
203293
func SaveConfig() error {
204294
configLock.Lock()
205295
defer configLock.Unlock()
@@ -218,6 +308,8 @@ func SaveConfig() error {
218308
return fmt.Errorf("failed to encode config: %w", err)
219309
}
220310

311+
SyncConfigSD(false)
312+
221313
return nil
222314
}
223315

@@ -226,3 +318,95 @@ func ensureConfigLoaded() {
226318
LoadConfig()
227319
}
228320
}
321+
322+
var systemInfoWriteLock sync.Mutex
323+
324+
func writeSystemInfoImg() error {
325+
systemInfoWriteLock.Lock()
326+
defer systemInfoWriteLock.Unlock()
327+
328+
imgPath := filepath.Join(imagesFolder, "system_info.img")
329+
unverifiedimgPath := filepath.Join(imagesFolder, "system_info.img") + ".unverified"
330+
mountPoint := "/mnt/system_info"
331+
332+
run := func(cmd string, args ...string) error {
333+
c := exec.Command(cmd, args...)
334+
c.Stdout = os.Stdout
335+
c.Stderr = os.Stderr
336+
return c.Run()
337+
}
338+
339+
if _, err := os.Stat(unverifiedimgPath); err == nil {
340+
err := os.Rename(unverifiedimgPath, imgPath)
341+
if err != nil {
342+
return fmt.Errorf("failed to rename %s to %s: %v", unverifiedimgPath, imgPath, err)
343+
}
344+
return nil
345+
}
346+
347+
isMounted := false
348+
if f, err := os.Open("/proc/mounts"); err == nil {
349+
defer f.Close()
350+
scanner := bufio.NewScanner(f)
351+
for scanner.Scan() {
352+
fields := strings.Fields(scanner.Text())
353+
if len(fields) >= 2 && fields[1] == mountPoint {
354+
isMounted = true
355+
break
356+
}
357+
}
358+
}
359+
360+
if isMounted {
361+
logger.Info().Msgf("%s is mounted, umounting...\n", mountPoint)
362+
_ = run("umount", mountPoint)
363+
}
364+
365+
if _, err := os.Stat(mountPoint); err == nil {
366+
if err := os.Remove(mountPoint); err != nil {
367+
return fmt.Errorf("failed to remove %s: %v", mountPoint, err)
368+
}
369+
}
370+
371+
if _, err := os.Stat(imgPath); err == nil {
372+
if err := copyFile(imgPath, unverifiedimgPath); err != nil {
373+
logger.Error().Err(err).Msg("failed to copy system_info.img")
374+
return err
375+
}
376+
} else {
377+
if err := run("dd", "if=/dev/zero", "of="+unverifiedimgPath, "bs=1M", "count=4"); err != nil {
378+
return fmt.Errorf("dd failed: %v", err)
379+
}
380+
381+
if err := run("mkfs.vfat", unverifiedimgPath); err != nil {
382+
return fmt.Errorf("mkfs.vfat failed: %v", err)
383+
}
384+
}
385+
386+
if err := os.MkdirAll(mountPoint, 0755); err != nil {
387+
return fmt.Errorf("mkdir failed: %v", err)
388+
}
389+
390+
if err := run("mount", "-o", "loop", unverifiedimgPath, mountPoint); err != nil {
391+
return fmt.Errorf("mount failed: %v", err)
392+
}
393+
394+
if err := run("cp", "/etc/hostname", mountPoint+"/hostname.txt"); err != nil {
395+
return fmt.Errorf("copy hostname failed: %v", err)
396+
}
397+
if err := run("sh", "-c", "ip addr show > "+mountPoint+"/network_info.txt"); err != nil {
398+
return fmt.Errorf("write network info failed: %v", err)
399+
}
400+
401+
_ = run("umount", mountPoint)
402+
if err := os.RemoveAll(mountPoint); err != nil {
403+
return fmt.Errorf("failed to remove %s: %v", mountPoint, err)
404+
}
405+
406+
if err := os.Rename(unverifiedimgPath, imgPath); err != nil {
407+
return fmt.Errorf("failed to rename %s to %s: %v", unverifiedimgPath, imgPath, err)
408+
}
409+
410+
logger.Info().Msg("system_info.img update successfully")
411+
return nil
412+
}

display.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,18 +109,21 @@ func updateDisplay() {
109109
} else {
110110
_, _ = lvObjSetState("Main", "USB_DISCONNECTED")
111111
}
112+
_ = os.WriteFile("/userdata/usb_state", []byte(usbState), 0644)
113+
112114
if lastVideoState.Ready {
113115
_, _ = lvObjSetState("Main", "HDMI_CONNECTED")
116+
_ = os.WriteFile("/userdata/hdmi_state", []byte("connected"), 0644)
114117
} else {
115118
_, _ = lvObjSetState("Main", "HDMI_DISCONNECTED")
119+
_ = os.WriteFile("/userdata/hdmi_state", []byte("disconnected"), 0644)
116120
}
117121

118122
if networkState.IsUp() {
119123
_, _ = lvObjSetState("Network", "NETWORK")
120124
} else {
121125
_, _ = lvObjSetState("Network", "NO_NETWORK")
122126
}
123-
124127
}
125128

126129
var (

internal/network/config.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ type NetworkConfig struct {
3636
Hostname null.String `json:"hostname,omitempty" validate_type:"hostname"`
3737
Domain null.String `json:"domain,omitempty" validate_type:"hostname"`
3838

39-
IPv4Mode null.String `json:"ipv4_mode,omitempty" one_of:"dhcp,static,disabled" default:"dhcp"`
40-
IPv4Static *IPv4StaticConfig `json:"ipv4_static,omitempty" required_if:"IPv4Mode=static"`
39+
IPv4Mode null.String `json:"ipv4_mode,omitempty" one_of:"dhcp,static,disabled" default:"dhcp"`
40+
IPv4RequestAddress null.String `json:"ipv4_request_address,omitempty"`
41+
IPv4Static *IPv4StaticConfig `json:"ipv4_static,omitempty" required_if:"IPv4Mode=static"`
4142

4243
IPv6Mode null.String `json:"ipv6_mode,omitempty" one_of:"slaac,dhcpv6,slaac_and_dhcpv6,static,link_local,disabled" default:"slaac"`
4344
IPv6Static *IPv6StaticConfig `json:"ipv6_static,omitempty" required_if:"IPv6Mode=static"`

internal/network/netif.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ func NewNetworkInterfaceState(opts *NetworkInterfaceOptions) (*NetworkInterfaceS
9595

9696
opts.OnDhcpLeaseChange(lease)
9797
},
98+
RequestAddress: s.config.IPv4RequestAddress.String,
9899
})
99100

100101
s.dhcpClient = dhcpClient

0 commit comments

Comments
 (0)