diff --git a/go.mod b/go.mod index a335646..dced2da 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/srwiley/oksvg v0.0.0-20210519022825-9fc0c575d5fe // indirect github.com/srwiley/rasterx v0.0.0-20210519020934-456a8d69b780 // indirect github.com/yuin/goldmark v1.4.1 // indirect - go.arsenm.dev/infinitime v0.0.0-20211122091416-ec43bad46652 + go.arsenm.dev/infinitime v0.0.0-20211123052001-ec1548ec0f30 golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0 // indirect golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect diff --git a/go.sum b/go.sum index bdf33d7..ac53c58 100644 --- a/go.sum +++ b/go.sum @@ -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.4.1 h1:/vn0k+RBvwlxEmP5E7SZMqNxPhfMVFEJiykr15/0XKM= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.arsenm.dev/infinitime v0.0.0-20211122091416-ec43bad46652 h1:2Z09crdXIs+aMy1xwuD6w2kml+EObfmzgCBaOxoZIv0= -go.arsenm.dev/infinitime v0.0.0-20211122091416-ec43bad46652/go.mod h1:kNBKxQfqeLUfi13GM6tB1kSvLm8HlZ7PM47AYeJQIiw= +go.arsenm.dev/infinitime v0.0.0-20211123052001-ec1548ec0f30 h1:nhuJfwWxBxfolMU5go3rBLhvl59HMRIMqEKi405Ja9w= +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/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= diff --git a/internal/types/types.go b/internal/types/types.go index 7712570..5268b28 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -15,6 +15,7 @@ const ( ReqTypeStepCount ReqTypeWatchStepCount ReqTypeCancel + ReqTypeFS ) const ( @@ -22,6 +23,21 @@ const ( 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 int Files []string @@ -56,3 +72,10 @@ type MotionValues struct { Y int16 Z int16 } + +type FileInfo struct { + Name string `json:"name"` + Size int64 `json:"size"` + IsDir bool `json:"isDir"` + +} \ No newline at end of file diff --git a/socket.go b/socket.go index d5bfe72..4ed7c76 100644 --- a/socket.go +++ b/socket.go @@ -22,6 +22,7 @@ import ( "bufio" "encoding/json" "fmt" + "io" "net" "os" "path/filepath" @@ -100,6 +101,11 @@ func startSocket(dev *infinitime.Device) error { func handleConnection(conn net.Conn, dev *infinitime.Device) { defer conn.Close() + fs, err := dev.FS() + if err != nil { + connErr(conn, 0, nil, "Error getting device filesystem") + } + // Create new scanner on connection scanner := bufio.NewScanner(conn) for scanner.Scan() { @@ -431,6 +437,109 @@ func handleConnection(conn net.Conn, dev *infinitime.Device) { break } 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: if req.Data == nil { connErr(conn, req.Type, nil, "No data provided. Cancel request requires request ID string as data.")