Compare commits
8 Commits
v0.0.4
...
2e8c825fff
| Author | SHA1 | Date | |
|---|---|---|---|
| 2e8c825fff | |||
| 7b870950d1 | |||
| 3a877c41a4 | |||
| 04fb390bee | |||
| 50b17d3266 | |||
| 763d408405 | |||
| fbb7cd9bc1 | |||
| f1b7f70313 |
95
api/fs.go
Normal file
95
api/fs.go
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
"go.arsenm.dev/itd/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Client) Rename(old, new string) error {
|
||||||
|
_, err := c.request(types.Request{
|
||||||
|
Type: types.ReqTypeFS,
|
||||||
|
Data: types.ReqDataFS{
|
||||||
|
Type: types.FSTypeMove,
|
||||||
|
Files: []string{old, new},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Remove(path string) error {
|
||||||
|
_, err := c.request(types.Request{
|
||||||
|
Type: types.ReqTypeFS,
|
||||||
|
Data: types.ReqDataFS{
|
||||||
|
Type: types.FSTypeDelete,
|
||||||
|
Files: []string{path},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Mkdir(path string) error {
|
||||||
|
_, err := c.request(types.Request{
|
||||||
|
Type: types.ReqTypeFS,
|
||||||
|
Data: types.ReqDataFS{
|
||||||
|
Type: types.FSTypeMkdir,
|
||||||
|
Files: []string{path},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ReadDir(path string) ([]types.FileInfo, error) {
|
||||||
|
res, err := c.request(types.Request{
|
||||||
|
Type: types.ReqTypeFS,
|
||||||
|
Data: types.ReqDataFS{
|
||||||
|
Type: types.FSTypeList,
|
||||||
|
Files: []string{path},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var out []types.FileInfo
|
||||||
|
err = mapstructure.Decode(res.Value, &out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ReadFile(path string) (string, error) {
|
||||||
|
res, err := c.request(types.Request{
|
||||||
|
Type: types.ReqTypeFS,
|
||||||
|
Data: types.ReqDataFS{
|
||||||
|
Type: types.FSTypeRead,
|
||||||
|
Files: []string{path},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return res.Value.(string), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) WriteFile(path, data string) error {
|
||||||
|
_, err := c.request(types.Request{
|
||||||
|
Type: types.ReqTypeFS,
|
||||||
|
Data: types.ReqDataFS{
|
||||||
|
Type: types.FSTypeRead,
|
||||||
|
Files: []string{path},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -19,6 +19,9 @@
|
|||||||
package firmware
|
package firmware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/cheggaaa/pb/v3"
|
"github.com/cheggaaa/pb/v3"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -38,6 +41,8 @@ var upgradeCmd = &cobra.Command{
|
|||||||
Short: "Upgrade InfiniTime firmware using files or archive",
|
Short: "Upgrade InfiniTime firmware using files or archive",
|
||||||
Aliases: []string{"upg"},
|
Aliases: []string{"upg"},
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
client := viper.Get("client").(*api.Client)
|
client := viper.Get("client").(*api.Client)
|
||||||
|
|
||||||
var upgType api.UpgradeType
|
var upgType api.UpgradeType
|
||||||
@@ -79,6 +84,9 @@ var upgradeCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
// Finish progress bar
|
// Finish progress bar
|
||||||
bar.Finish()
|
bar.Finish()
|
||||||
|
|
||||||
|
fmt.Printf("Transferred %d B in %s.\n", bar.Total(), time.Since(start))
|
||||||
|
fmt.Println("Remember to validate the new firmware in the InfiniTime settings.")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -134,8 +134,6 @@ func upgradeTab(parent fyne.Window, client *api.Client) *fyne.Container {
|
|||||||
|
|
||||||
// Show progress dialog
|
// Show progress dialog
|
||||||
progressDlg.Show()
|
progressDlg.Show()
|
||||||
// Hide progress dialog after completion
|
|
||||||
defer progressDlg.Hide()
|
|
||||||
|
|
||||||
for event := range progress {
|
for event := range progress {
|
||||||
// Set label text to received / total B
|
// Set label text to received / total B
|
||||||
@@ -150,6 +148,24 @@ func upgradeTab(parent fyne.Window, client *api.Client) *fyne.Container {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hide progress dialog after completion
|
||||||
|
progressDlg.Hide()
|
||||||
|
|
||||||
|
// Reset screen to default
|
||||||
|
upgradeTypeSelect.SetSelectedIndex(0)
|
||||||
|
firmwareBtn.SetText("Select firmware (.bin)")
|
||||||
|
initPktBtn.SetText("Select init packet (.dat)")
|
||||||
|
archiveBtn.SetText("Select archive (.zip)")
|
||||||
|
firmwarePath = ""
|
||||||
|
initPktPath = ""
|
||||||
|
archivePath = ""
|
||||||
|
|
||||||
|
dialog.NewInformation(
|
||||||
|
"Upgrade Complete",
|
||||||
|
"The firmware was transferred successfully.\nRemember to validate the firmware in InfiniTime settings.",
|
||||||
|
parent,
|
||||||
|
).Show()
|
||||||
})
|
})
|
||||||
|
|
||||||
// Return container containing all elements
|
// Return container containing all elements
|
||||||
|
|||||||
@@ -28,17 +28,21 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setCfgDefaults() {
|
func setCfgDefaults() {
|
||||||
viper.SetDefault("cfg.version", 2)
|
|
||||||
|
|
||||||
viper.SetDefault("socket.path", "/tmp/itd/socket")
|
viper.SetDefault("socket.path", "/tmp/itd/socket")
|
||||||
|
|
||||||
viper.SetDefault("conn.reconnect", true)
|
viper.SetDefault("conn.reconnect", true)
|
||||||
|
|
||||||
|
viper.SetDefault("conn.whitelist.enabled", false)
|
||||||
|
viper.SetDefault("conn.whitelist.devices", []string{})
|
||||||
|
|
||||||
viper.SetDefault("on.connect.notify", true)
|
viper.SetDefault("on.connect.notify", true)
|
||||||
|
|
||||||
viper.SetDefault("on.reconnect.notify", true)
|
viper.SetDefault("on.reconnect.notify", true)
|
||||||
viper.SetDefault("on.reconnect.setTime", true)
|
viper.SetDefault("on.reconnect.setTime", true)
|
||||||
|
|
||||||
|
viper.SetDefault("notifs.translit.use", []string{"eASCII"})
|
||||||
|
viper.SetDefault("notifs.translit.custom", []string{})
|
||||||
|
|
||||||
viper.SetDefault("notifs.ignore.sender", []string{})
|
viper.SetDefault("notifs.ignore.sender", []string{})
|
||||||
viper.SetDefault("notifs.ignore.summary", []string{"InfiniTime"})
|
viper.SetDefault("notifs.ignore.summary", []string{"InfiniTime"})
|
||||||
viper.SetDefault("notifs.ignore.body", []string{})
|
viper.SetDefault("notifs.ignore.body", []string{})
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -25,7 +25,7 @@ require (
|
|||||||
github.com/srwiley/oksvg v0.0.0-20210519022825-9fc0c575d5fe // indirect
|
github.com/srwiley/oksvg v0.0.0-20210519022825-9fc0c575d5fe // indirect
|
||||||
github.com/srwiley/rasterx v0.0.0-20210519020934-456a8d69b780 // indirect
|
github.com/srwiley/rasterx v0.0.0-20210519020934-456a8d69b780 // indirect
|
||||||
github.com/yuin/goldmark v1.4.1 // indirect
|
github.com/yuin/goldmark v1.4.1 // indirect
|
||||||
go.arsenm.dev/infinitime v0.0.0-20211023042633-53aa6f8a0c72
|
go.arsenm.dev/infinitime v0.0.0-20211123052001-ec1548ec0f30
|
||||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect
|
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect
|
||||||
golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0 // indirect
|
golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0 // indirect
|
||||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
|
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -287,8 +287,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
|||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mozillazg/go-pinyin v0.18.0 h1:hQompXO23/0ohH8YNjvfsAITnCQImCiR/Fny8EhIeW0=
|
github.com/mozillazg/go-pinyin v0.18.0 h1:hQompXO23/0ohH8YNjvfsAITnCQImCiR/Fny8EhIeW0=
|
||||||
github.com/mozillazg/go-pinyin v0.18.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc=
|
github.com/mozillazg/go-pinyin v0.18.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc=
|
||||||
github.com/muka/go-bluetooth v0.0.0-20210812063148-b6c83362e27d h1:EG/xyWjHT19rkUpwsWSkyiCCmyqNwFovr9m10rhyOxU=
|
github.com/muka/go-bluetooth v0.0.0-20211122080231-b99792bbe62a h1:KxRXeSWoBM5FCPAnSUYxt1qwEzmoH/K7upb4fiSDwdc=
|
||||||
github.com/muka/go-bluetooth v0.0.0-20210812063148-b6c83362e27d/go.mod h1:dMCjicU6vRBk34dqOmIZm0aod6gUwZXOXzBROqGous0=
|
github.com/muka/go-bluetooth v0.0.0-20211122080231-b99792bbe62a/go.mod h1:dMCjicU6vRBk34dqOmIZm0aod6gUwZXOXzBROqGous0=
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
@@ -367,8 +367,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
|||||||
github.com/yuin/goldmark v1.3.8/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.8/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.1 h1:/vn0k+RBvwlxEmP5E7SZMqNxPhfMVFEJiykr15/0XKM=
|
github.com/yuin/goldmark v1.4.1 h1:/vn0k+RBvwlxEmP5E7SZMqNxPhfMVFEJiykr15/0XKM=
|
||||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.arsenm.dev/infinitime v0.0.0-20211023042633-53aa6f8a0c72 h1:e8kOuL6Jj8ZjJzkGwJ3xqpGG9EhUzfvZk9AlSsm3X1U=
|
go.arsenm.dev/infinitime v0.0.0-20211123052001-ec1548ec0f30 h1:nhuJfwWxBxfolMU5go3rBLhvl59HMRIMqEKi405Ja9w=
|
||||||
go.arsenm.dev/infinitime v0.0.0-20211023042633-53aa6f8a0c72/go.mod h1:gaepaueUz4J5FfxuV19B4w5pi+V3mD0LTef50ryxr/Q=
|
go.arsenm.dev/infinitime v0.0.0-20211123052001-ec1548ec0f30/go.mod h1:kNBKxQfqeLUfi13GM6tB1kSvLm8HlZ7PM47AYeJQIiw=
|
||||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||||
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ReqTypeHeartRate = iota
|
ReqTypeHeartRate = iota
|
||||||
ReqTypeBattLevel
|
ReqTypeBattLevel
|
||||||
@@ -15,6 +20,7 @@ const (
|
|||||||
ReqTypeStepCount
|
ReqTypeStepCount
|
||||||
ReqTypeWatchStepCount
|
ReqTypeWatchStepCount
|
||||||
ReqTypeCancel
|
ReqTypeCancel
|
||||||
|
ReqTypeFS
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -22,6 +28,21 @@ const (
|
|||||||
UpgradeTypeFiles
|
UpgradeTypeFiles
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
FSTypeWrite = iota
|
||||||
|
FSTypeRead
|
||||||
|
FSTypeMove
|
||||||
|
FSTypeDelete
|
||||||
|
FSTypeList
|
||||||
|
FSTypeMkdir
|
||||||
|
)
|
||||||
|
|
||||||
|
type ReqDataFS struct {
|
||||||
|
Type int `json:"type"`
|
||||||
|
Files []string `json:"files"`
|
||||||
|
Data string `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type ReqDataFwUpgrade struct {
|
type ReqDataFwUpgrade struct {
|
||||||
Type int
|
Type int
|
||||||
Files []string
|
Files []string
|
||||||
@@ -56,3 +77,66 @@ type MotionValues struct {
|
|||||||
Y int16
|
Y int16
|
||||||
Z int16
|
Z int16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
IsDir bool `json:"isDir"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi FileInfo) String() string {
|
||||||
|
var isDirChar rune
|
||||||
|
if fi.IsDir {
|
||||||
|
isDirChar = 'd'
|
||||||
|
} else {
|
||||||
|
isDirChar = '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get human-readable value for file size
|
||||||
|
val, unit := bytesHuman(fi.Size)
|
||||||
|
prec := 0
|
||||||
|
// If value is less than 10, set precision to 1
|
||||||
|
if val < 10 {
|
||||||
|
prec = 1
|
||||||
|
}
|
||||||
|
// Convert float to string
|
||||||
|
valStr := strconv.FormatFloat(val, 'f', prec, 64)
|
||||||
|
|
||||||
|
// Return string formatted like so:
|
||||||
|
// - 10 kB file
|
||||||
|
// or:
|
||||||
|
// d 0 B .
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"%c %3s %-2s %s",
|
||||||
|
isDirChar,
|
||||||
|
valStr,
|
||||||
|
unit,
|
||||||
|
fi.Name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bytesHuman returns a human-readable string for
|
||||||
|
// the amount of bytes inputted.
|
||||||
|
func bytesHuman(b int64) (float64, string) {
|
||||||
|
const unit = 1000
|
||||||
|
// Set possible units prefixes (PineTime flash is 4MB)
|
||||||
|
units := [2]rune{'k', 'M'}
|
||||||
|
// If amount of bytes is less than smallest unit
|
||||||
|
if b < unit {
|
||||||
|
// Return unchanged with unit "B"
|
||||||
|
return float64(b), "B"
|
||||||
|
}
|
||||||
|
|
||||||
|
div, exp := int64(unit), 0
|
||||||
|
// Get decimal values and unit prefix index
|
||||||
|
for n := b / unit; n >= unit; n /= unit {
|
||||||
|
div *= unit
|
||||||
|
exp++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create string for full unit
|
||||||
|
unitStr := string([]rune{units[exp], 'B'})
|
||||||
|
|
||||||
|
// Return decimal with unit string
|
||||||
|
return float64(b) / float64(div), unitStr
|
||||||
|
}
|
||||||
|
|||||||
8
itd.toml
8
itd.toml
@@ -1,13 +1,13 @@
|
|||||||
# This is temporary, it is to show a notice
|
|
||||||
# to people still using the old config
|
|
||||||
cfg.version = 2
|
|
||||||
|
|
||||||
[socket]
|
[socket]
|
||||||
path = "/tmp/itd/socket"
|
path = "/tmp/itd/socket"
|
||||||
|
|
||||||
[conn]
|
[conn]
|
||||||
reconnect = true
|
reconnect = true
|
||||||
|
|
||||||
|
[conn.whitelist]
|
||||||
|
enabled = false
|
||||||
|
devices = []
|
||||||
|
|
||||||
[on.connect]
|
[on.connect]
|
||||||
notify = true
|
notify = true
|
||||||
|
|
||||||
|
|||||||
7
main.go
7
main.go
@@ -29,16 +29,15 @@ import (
|
|||||||
var firmwareUpdating = false
|
var firmwareUpdating = false
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if viper.GetInt("cfg.version") != 2 {
|
infinitime.Init()
|
||||||
log.Fatal().Msg("Please update your config to the newest format, only v2 configs supported.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanly exit after function
|
// Cleanly exit after function
|
||||||
defer infinitime.Exit()
|
defer infinitime.Exit()
|
||||||
|
|
||||||
// Connect to InfiniTime with default options
|
// Connect to InfiniTime with default options
|
||||||
dev, err := infinitime.Connect(&infinitime.Options{
|
dev, err := infinitime.Connect(&infinitime.Options{
|
||||||
AttemptReconnect: viper.GetBool("conn.reconnect"),
|
AttemptReconnect: viper.GetBool("conn.reconnect"),
|
||||||
|
WhitelistEnabled: viper.GetBool("conn.whitelist.enabled"),
|
||||||
|
Whitelist: viper.GetStringSlice("conn.whitelist.devices"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Error connecting to InfiniTime")
|
log.Error().Err(err).Msg("Error connecting to InfiniTime")
|
||||||
|
|||||||
109
socket.go
109
socket.go
@@ -22,6 +22,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -100,6 +101,11 @@ func startSocket(dev *infinitime.Device) error {
|
|||||||
func handleConnection(conn net.Conn, dev *infinitime.Device) {
|
func handleConnection(conn net.Conn, dev *infinitime.Device) {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
|
fs, err := dev.FS()
|
||||||
|
if err != nil {
|
||||||
|
connErr(conn, 0, nil, "Error getting device filesystem")
|
||||||
|
}
|
||||||
|
|
||||||
// Create new scanner on connection
|
// Create new scanner on connection
|
||||||
scanner := bufio.NewScanner(conn)
|
scanner := bufio.NewScanner(conn)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
@@ -431,6 +437,109 @@ func handleConnection(conn net.Conn, dev *infinitime.Device) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
firmwareUpdating = false
|
firmwareUpdating = false
|
||||||
|
case types.ReqTypeFS:
|
||||||
|
// If no data, return error
|
||||||
|
if req.Data == nil {
|
||||||
|
connErr(conn, req.Type, nil, "Data required for firmware upgrade request")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
var reqData types.ReqDataFS
|
||||||
|
// Decode data map to firmware upgrade request data
|
||||||
|
err = mapstructure.Decode(req.Data, &reqData)
|
||||||
|
if err != nil {
|
||||||
|
connErr(conn, req.Type, err, "Error decoding request data")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch reqData.Type {
|
||||||
|
case types.FSTypeDelete:
|
||||||
|
for _, file := range reqData.Files {
|
||||||
|
err := fs.Remove(file)
|
||||||
|
if err != nil {
|
||||||
|
connErr(conn, req.Type, err, "Error removing file")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case types.FSTypeMove:
|
||||||
|
if len(reqData.Files) != 2 {
|
||||||
|
connErr(conn, req.Type, nil, "Move FS command requires an old path and new path in the files list")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err := fs.Rename(reqData.Files[0], reqData.Files[1])
|
||||||
|
if err != nil {
|
||||||
|
connErr(conn, req.Type, err, "Error moving file")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case types.FSTypeMkdir:
|
||||||
|
for _, file := range reqData.Files {
|
||||||
|
err := fs.Mkdir(file)
|
||||||
|
if err != nil {
|
||||||
|
connErr(conn, req.Type, err, "Error creating directory")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case types.FSTypeList:
|
||||||
|
if len(reqData.Files) != 1 {
|
||||||
|
connErr(conn, req.Type, nil, "List FS command requires a path to list in the files list")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
entries, err := fs.ReadDir(reqData.Files[0])
|
||||||
|
if err != nil {
|
||||||
|
connErr(conn, req.Type, err, "Error reading directory")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
var out []types.FileInfo
|
||||||
|
for _, entry := range entries {
|
||||||
|
info, err := entry.Info()
|
||||||
|
if err != nil {
|
||||||
|
connErr(conn, req.Type, err, "Error getting file info")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
out = append(out, types.FileInfo{
|
||||||
|
Name: info.Name(),
|
||||||
|
Size: info.Size(),
|
||||||
|
IsDir: info.IsDir(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
json.NewEncoder(conn).Encode(types.Response{
|
||||||
|
Type: req.Type,
|
||||||
|
Value: out,
|
||||||
|
})
|
||||||
|
case types.FSTypeWrite:
|
||||||
|
if len(reqData.Files) != 1 {
|
||||||
|
connErr(conn, req.Type, nil, "Write FS command requires a path to the file to write")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
file, err := fs.Create(reqData.Files[0], uint32(len(reqData.Data)))
|
||||||
|
if err != nil {
|
||||||
|
connErr(conn, req.Type, err, "Error creating file")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_, err = file.WriteString(reqData.Data)
|
||||||
|
if err != nil {
|
||||||
|
connErr(conn, req.Type, err, "Error writing to file")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
json.NewEncoder(conn).Encode(types.Response{Type: req.Type})
|
||||||
|
case types.FSTypeRead:
|
||||||
|
if len(reqData.Files) != 1 {
|
||||||
|
connErr(conn, req.Type, nil, "Read FS command requires a path to the file to read")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
file, err := fs.Open(reqData.Files[0])
|
||||||
|
if err != nil {
|
||||||
|
connErr(conn, req.Type, err, "Error opening file")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
data, err := io.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
connErr(conn, req.Type, err, "Error reading from file")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
json.NewEncoder(conn).Encode(types.Response{
|
||||||
|
Type: req.Type,
|
||||||
|
Value: string(data),
|
||||||
|
})
|
||||||
|
}
|
||||||
case types.ReqTypeCancel:
|
case types.ReqTypeCancel:
|
||||||
if req.Data == nil {
|
if req.Data == nil {
|
||||||
connErr(conn, req.Type, nil, "No data provided. Cancel request requires request ID string as data.")
|
connErr(conn, req.Type, nil, "No data provided. Cancel request requires request ID string as data.")
|
||||||
|
|||||||
Reference in New Issue
Block a user