mirror of
https://github.com/wisplite/parchment.git
synced 2026-06-27 13:47:08 -05:00
Refactor UI state management and improve error handling in the application. Added success and error messages to enhance user feedback during package creation and device connection status updates.
This commit is contained in:
@@ -2,28 +2,26 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
|
||||||
"log"
|
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type fileData struct {
|
type fileData struct {
|
||||||
name string
|
name string
|
||||||
content []byte
|
content []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type cpkg struct {
|
type cpkg struct {
|
||||||
packageName string
|
packageName string
|
||||||
files []fileData
|
files []fileData
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCpkg(packageName string) *cpkg {
|
func NewCpkg(packageName string) *cpkg {
|
||||||
return &cpkg{
|
return &cpkg{
|
||||||
packageName: packageName,
|
packageName: packageName,
|
||||||
files: make([]fileData, 0),
|
files: make([]fileData, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,12 +42,12 @@ func (c *cpkg) createCpkgFileHeader(file fileData) []byte {
|
|||||||
headerBytes := make([]byte, 0)
|
headerBytes := make([]byte, 0)
|
||||||
headerBytes = append(headerBytes, byte(len(file.name)))
|
headerBytes = append(headerBytes, byte(len(file.name)))
|
||||||
headerBytes = append(headerBytes, []byte(file.name)...)
|
headerBytes = append(headerBytes, []byte(file.name)...)
|
||||||
|
|
||||||
// file size (uint32 - 4 bytes)
|
// file size (uint32 - 4 bytes)
|
||||||
fileSizeBytes := make([]byte, 4)
|
fileSizeBytes := make([]byte, 4)
|
||||||
binary.LittleEndian.PutUint32(fileSizeBytes, uint32(len(file.content)))
|
binary.LittleEndian.PutUint32(fileSizeBytes, uint32(len(file.content)))
|
||||||
headerBytes = append(headerBytes, fileSizeBytes...)
|
headerBytes = append(headerBytes, fileSizeBytes...)
|
||||||
|
|
||||||
return headerBytes
|
return headerBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,17 +58,17 @@ func (c *cpkg) createCpkgFileHeader(file fileData) []byte {
|
|||||||
func (c *cpkg) createCpkgHeader() []byte {
|
func (c *cpkg) createCpkgHeader() []byte {
|
||||||
headerBytes := make([]byte, 0)
|
headerBytes := make([]byte, 0)
|
||||||
headerBytes = append(headerBytes, []byte("Cpkg")...)
|
headerBytes = append(headerBytes, []byte("Cpkg")...)
|
||||||
|
|
||||||
// version (uint16 - 2 bytes)
|
// version (uint16 - 2 bytes)
|
||||||
versionBytes := make([]byte, 2)
|
versionBytes := make([]byte, 2)
|
||||||
binary.LittleEndian.PutUint16(versionBytes, 1)
|
binary.LittleEndian.PutUint16(versionBytes, 1)
|
||||||
headerBytes = append(headerBytes, versionBytes...)
|
headerBytes = append(headerBytes, versionBytes...)
|
||||||
|
|
||||||
// file count (uint32 - 4 bytes)
|
// file count (uint32 - 4 bytes)
|
||||||
fileCountBytes := make([]byte, 4)
|
fileCountBytes := make([]byte, 4)
|
||||||
binary.LittleEndian.PutUint32(fileCountBytes, uint32(len(c.files)))
|
binary.LittleEndian.PutUint32(fileCountBytes, uint32(len(c.files)))
|
||||||
headerBytes = append(headerBytes, fileCountBytes...)
|
headerBytes = append(headerBytes, fileCountBytes...)
|
||||||
|
|
||||||
return headerBytes
|
return headerBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +78,7 @@ func (c *cpkg) Create() (bool, error) {
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
// Write main header
|
// Write main header
|
||||||
header := c.createCpkgHeader()
|
header := c.createCpkgHeader()
|
||||||
n, err := file.Write(header)
|
n, err := file.Write(header)
|
||||||
@@ -90,7 +88,7 @@ func (c *cpkg) Create() (bool, error) {
|
|||||||
if n != len(header) {
|
if n != len(header) {
|
||||||
return false, fmt.Errorf("incomplete header write: wrote %d of %d bytes", n, len(header))
|
return false, fmt.Errorf("incomplete header write: wrote %d of %d bytes", n, len(header))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write each file
|
// Write each file
|
||||||
for i, fileData := range c.files {
|
for i, fileData := range c.files {
|
||||||
// Write file header
|
// Write file header
|
||||||
@@ -102,7 +100,7 @@ func (c *cpkg) Create() (bool, error) {
|
|||||||
if n != len(fileHeader) {
|
if n != len(fileHeader) {
|
||||||
return false, fmt.Errorf("incomplete header write for file %d (%s): wrote %d of %d bytes", i, fileData.name, n, len(fileHeader))
|
return false, fmt.Errorf("incomplete header write for file %d (%s): wrote %d of %d bytes", i, fileData.name, n, len(fileHeader))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write file content
|
// Write file content
|
||||||
n, err = file.Write(fileData.content)
|
n, err = file.Write(fileData.content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -111,21 +109,10 @@ func (c *cpkg) Create() (bool, error) {
|
|||||||
if n != len(fileData.content) {
|
if n != len(fileData.content) {
|
||||||
return false, fmt.Errorf("incomplete content write for file %d (%s): wrote %d of %d bytes", i, fileData.name, n, len(fileData.content))
|
return false, fmt.Errorf("incomplete content write for file %d (%s): wrote %d of %d bytes", i, fileData.name, n, len(fileData.content))
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Wrote file %d: %s (%d bytes)", i, fileData.name, len(fileData.content))
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cpkg) DebugPrint() {
|
|
||||||
log.Println("Package Name:", c.packageName)
|
|
||||||
idx := 0
|
|
||||||
for _, file := range c.files {
|
|
||||||
log.Println("File " + strconv.Itoa(idx) + " header")
|
|
||||||
log.Println(c.createCpkgFileHeader(file))
|
|
||||||
idx++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cpkg) Unpack(fsys fs.FS) error {
|
func (c *cpkg) Unpack(fsys fs.FS) error {
|
||||||
@@ -134,33 +121,32 @@ func (c *cpkg) Unpack(fsys fs.FS) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
// Read main header (10 bytes)
|
// Read main header (10 bytes)
|
||||||
header := make([]byte, 10)
|
header := make([]byte, 10)
|
||||||
_, err = file.Read(header)
|
_, err = file.Read(header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read header: %w", err)
|
return fmt.Errorf("failed to read header: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify magic number
|
// Verify magic number
|
||||||
magicNumber := string(header[:4])
|
magicNumber := string(header[:4])
|
||||||
if magicNumber != "Cpkg" {
|
if magicNumber != "Cpkg" {
|
||||||
return fmt.Errorf("invalid cpkg file: wrong magic number")
|
return fmt.Errorf("invalid cpkg file: wrong magic number")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify version
|
// Verify version
|
||||||
version := binary.LittleEndian.Uint16(header[4:6])
|
version := binary.LittleEndian.Uint16(header[4:6])
|
||||||
if version != 1 {
|
if version != 1 {
|
||||||
return fmt.Errorf("unsupported cpkg file version: %d", version)
|
return fmt.Errorf("unsupported cpkg file version: %d", version)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read file count
|
// Read file count
|
||||||
fileCount := binary.LittleEndian.Uint32(header[6:10])
|
fileCount := binary.LittleEndian.Uint32(header[6:10])
|
||||||
log.Printf("Unpacking %d files from %s.cpkg", fileCount, c.packageName)
|
|
||||||
|
|
||||||
// Clear existing files array
|
// Clear existing files array
|
||||||
c.files = make([]fileData, 0, fileCount)
|
c.files = make([]fileData, 0, fileCount)
|
||||||
|
|
||||||
// Read each file sequentially
|
// Read each file sequentially
|
||||||
for i := 0; i < int(fileCount); i++ {
|
for i := 0; i < int(fileCount); i++ {
|
||||||
// Read filename length (1 byte)
|
// Read filename length (1 byte)
|
||||||
@@ -173,7 +159,7 @@ func (c *cpkg) Unpack(fsys fs.FS) error {
|
|||||||
return fmt.Errorf("incomplete read of filename length for file %d: got %d bytes, expected 1", i, n)
|
return fmt.Errorf("incomplete read of filename length for file %d: got %d bytes, expected 1", i, n)
|
||||||
}
|
}
|
||||||
fileNameLength := fileNameLengthBuf[0]
|
fileNameLength := fileNameLengthBuf[0]
|
||||||
|
|
||||||
// Read filename
|
// Read filename
|
||||||
fileNameBuf := make([]byte, fileNameLength)
|
fileNameBuf := make([]byte, fileNameLength)
|
||||||
n, err = file.Read(fileNameBuf)
|
n, err = file.Read(fileNameBuf)
|
||||||
@@ -184,7 +170,7 @@ func (c *cpkg) Unpack(fsys fs.FS) error {
|
|||||||
return fmt.Errorf("incomplete read of filename for file %d: got %d bytes, expected %d", i, n, fileNameLength)
|
return fmt.Errorf("incomplete read of filename for file %d: got %d bytes, expected %d", i, n, fileNameLength)
|
||||||
}
|
}
|
||||||
fileName := string(fileNameBuf)
|
fileName := string(fileNameBuf)
|
||||||
|
|
||||||
// Read file size (4 bytes)
|
// Read file size (4 bytes)
|
||||||
fileSizeBuf := make([]byte, 4)
|
fileSizeBuf := make([]byte, 4)
|
||||||
n, err = file.Read(fileSizeBuf)
|
n, err = file.Read(fileSizeBuf)
|
||||||
@@ -195,7 +181,7 @@ func (c *cpkg) Unpack(fsys fs.FS) error {
|
|||||||
return fmt.Errorf("incomplete read of file size for file %d: got %d bytes, expected 4", i, n)
|
return fmt.Errorf("incomplete read of file size for file %d: got %d bytes, expected 4", i, n)
|
||||||
}
|
}
|
||||||
fileSize := binary.LittleEndian.Uint32(fileSizeBuf)
|
fileSize := binary.LittleEndian.Uint32(fileSizeBuf)
|
||||||
|
|
||||||
// Read file content
|
// Read file content
|
||||||
fileContent := make([]byte, fileSize)
|
fileContent := make([]byte, fileSize)
|
||||||
n, err = file.Read(fileContent)
|
n, err = file.Read(fileContent)
|
||||||
@@ -205,8 +191,7 @@ func (c *cpkg) Unpack(fsys fs.FS) error {
|
|||||||
if n != int(fileSize) {
|
if n != int(fileSize) {
|
||||||
return fmt.Errorf("incomplete read of content for file %d (%s): got %d bytes, expected %d", i, fileName, n, fileSize)
|
return fmt.Errorf("incomplete read of content for file %d (%s): got %d bytes, expected %d", i, fileName, n, fileSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Read file %d: %s (%d bytes)", i, fileName, fileSize)
|
|
||||||
c.files = append(c.files, fileData{name: fileName, content: fileContent})
|
c.files = append(c.files, fileData{name: fileName, content: fileContent})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,24 +200,22 @@ func (c *cpkg) Unpack(fsys fs.FS) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create output directory: %w", err)
|
return fmt.Errorf("failed to create output directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, fileData := range c.files {
|
for _, fileData := range c.files {
|
||||||
outputPath := filepath.Join(c.packageName, fileData.name)
|
outputPath := filepath.Join(c.packageName, fileData.name)
|
||||||
|
|
||||||
// Create parent directories if they don't exist
|
// Create parent directories if they don't exist
|
||||||
parentDir := filepath.Dir(outputPath)
|
parentDir := filepath.Dir(outputPath)
|
||||||
err = os.MkdirAll(parentDir, 0755)
|
err = os.MkdirAll(parentDir, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create directory for file %s: %w", fileData.name, err)
|
return fmt.Errorf("failed to create directory for file %s: %w", fileData.name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.WriteFile(outputPath, fileData.content, 0644)
|
err = os.WriteFile(outputPath, fileData.content, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to write file %s: %w", fileData.name, err)
|
return fmt.Errorf("failed to write file %s: %w", fileData.name, err)
|
||||||
}
|
}
|
||||||
log.Printf("Wrote file: %s", outputPath)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Successfully unpacked %d files to %s/", len(c.files), c.packageName)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,13 +68,18 @@ func (d *Device) Connect() error {
|
|||||||
|
|
||||||
// ExitDevMode sends the command to exit dev mode.
|
// ExitDevMode sends the command to exit dev mode.
|
||||||
func (d *Device) ExitDevMode() error {
|
func (d *Device) ExitDevMode() error {
|
||||||
if !d.Connected || d.Port == nil {
|
if d.Port == nil {
|
||||||
return fmt.Errorf("device not connected")
|
return fmt.Errorf("port not open")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send exit dev mode command
|
// disable dev mode
|
||||||
// TODO: Replace with the actual command sequence to exit dev mode
|
_, err := d.Port.Write([]byte{0xAA, 0x05, 0x00, 0x00, 0x00})
|
||||||
// This is currently not implemented on the Cardputer side.
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to send exit dev mode command: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow some time for the device to respond or settle if needed
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ require (
|
|||||||
github.com/creack/goselect v0.1.2 // indirect
|
github.com/creack/goselect v0.1.2 // indirect
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||||
github.com/gdamore/encoding v1.0.1 // indirect
|
github.com/gdamore/encoding v1.0.1 // indirect
|
||||||
github.com/gdamore/tcell/v2 v2.8.1 // indirect
|
github.com/gdamore/tcell/v2 v2.9.0 // indirect
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||||
@@ -23,11 +23,12 @@ require (
|
|||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
github.com/muesli/termenv v0.16.0 // indirect
|
github.com/muesli/termenv v0.16.0 // indirect
|
||||||
|
github.com/navidys/tvxwidgets v0.12.1 // indirect
|
||||||
github.com/rivo/tview v0.42.1-0.20250929082832-e113793670e2 // indirect
|
github.com/rivo/tview v0.42.1-0.20250929082832-e113793670e2 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
go.bug.st/serial v1.6.4 // indirect
|
go.bug.st/serial v1.6.4 // indirect
|
||||||
golang.org/x/sys v0.36.0 // indirect
|
golang.org/x/sys v0.36.0 // indirect
|
||||||
golang.org/x/term v0.28.0 // indirect
|
golang.org/x/term v0.34.0 // indirect
|
||||||
golang.org/x/text v0.21.0 // indirect
|
golang.org/x/text v0.28.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uh
|
|||||||
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
|
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
|
||||||
github.com/gdamore/tcell/v2 v2.8.1 h1:KPNxyqclpWpWQlPLx6Xui1pMk8S+7+R37h3g07997NU=
|
github.com/gdamore/tcell/v2 v2.8.1 h1:KPNxyqclpWpWQlPLx6Xui1pMk8S+7+R37h3g07997NU=
|
||||||
github.com/gdamore/tcell/v2 v2.8.1/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
|
github.com/gdamore/tcell/v2 v2.8.1/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
|
||||||
|
github.com/gdamore/tcell/v2 v2.9.0 h1:N6t+eqK7/xwtRPwxzs1PXeRWnm0H9l02CrgJ7DLn1ys=
|
||||||
|
github.com/gdamore/tcell/v2 v2.9.0/go.mod h1:8/ZoqM9rxzYphT9tH/9LnunhV9oPBqwS8WHGYm5nrmo=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
@@ -39,6 +41,8 @@ github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELU
|
|||||||
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||||
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
||||||
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||||
|
github.com/navidys/tvxwidgets v0.12.1 h1:/5yJf/0MPlg50VKnaAfnRF1sBMPos/Aeb9tY0/UXJ3M=
|
||||||
|
github.com/navidys/tvxwidgets v0.12.1/go.mod h1:3EQbBvdokrZsEjnXKfOdcYAQk4dZIQSfmTJPxQbBE9A=
|
||||||
github.com/rivo/tview v0.42.1-0.20250929082832-e113793670e2 h1:0SWZkAwSpcwyWOTFxFOVjnB+nrUkHAPNnERVYfVzRow=
|
github.com/rivo/tview v0.42.1-0.20250929082832-e113793670e2 h1:0SWZkAwSpcwyWOTFxFOVjnB+nrUkHAPNnERVYfVzRow=
|
||||||
github.com/rivo/tview v0.42.1-0.20250929082832-e113793670e2/go.mod h1:cSfIYfhpSGCjp3r/ECJb+GKS7cGJnqV8vfjQPwoXyfY=
|
github.com/rivo/tview v0.42.1-0.20250929082832-e113793670e2/go.mod h1:cSfIYfhpSGCjp3r/ECJb+GKS7cGJnqV8vfjQPwoXyfY=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
@@ -102,6 +106,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
|||||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||||
|
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
|
||||||
|
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
@@ -114,6 +120,8 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
|
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||||
|
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
|||||||
@@ -24,7 +24,10 @@ func MonitorDevice(ctx context.Context, app *tview.Application, frame **tview.Fr
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if device.Connected {
|
if device.Connected {
|
||||||
device.Close()
|
device.Close()
|
||||||
UpdateDeviceStatus(app, *frame, state, "Cardputer disconnected", tcell.ColorRed)
|
state.Error = "Cardputer disconnected"
|
||||||
|
UpdateDeviceStatus(app, *frame, state, "Waiting for cardputer...", tcell.ColorWhite)
|
||||||
|
} else {
|
||||||
|
UpdateDeviceStatus(app, *frame, state, "Waiting for cardputer...", tcell.ColorWhite)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !device.Connected {
|
if !device.Connected {
|
||||||
@@ -34,6 +37,9 @@ func MonitorDevice(ctx context.Context, app *tview.Application, frame **tview.Fr
|
|||||||
UpdateDeviceStatus(app, *frame, state, "Error connecting to cardputer: "+err.Error(), tcell.ColorRed)
|
UpdateDeviceStatus(app, *frame, state, "Error connecting to cardputer: "+err.Error(), tcell.ColorRed)
|
||||||
} else {
|
} else {
|
||||||
UpdateDeviceStatus(app, *frame, state, "Connected to cardputer: "+port, tcell.ColorGreen)
|
UpdateDeviceStatus(app, *frame, state, "Connected to cardputer: "+port, tcell.ColorGreen)
|
||||||
|
if state.Error == "Cardputer disconnected" {
|
||||||
|
state.Error = ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
UpdateDeviceStatus(app, *frame, state, "Connected to cardputer: "+port, tcell.ColorGreen)
|
UpdateDeviceStatus(app, *frame, state, "Connected to cardputer: "+port, tcell.ColorGreen)
|
||||||
@@ -47,10 +53,21 @@ func main() {
|
|||||||
// Initialize Device manager
|
// Initialize Device manager
|
||||||
device := NewDevice()
|
device := NewDevice()
|
||||||
|
|
||||||
|
// Ensure cleanup happens no matter how we exit
|
||||||
|
defer func() {
|
||||||
|
log.Println("Cleanup: Disconnecting device...")
|
||||||
|
if err := device.Close(); err != nil {
|
||||||
|
log.Printf("Cleanup: Error disconnecting device: %v\n", err)
|
||||||
|
} else {
|
||||||
|
log.Println("Cleanup: Device disconnected successfully")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
app := tview.NewApplication()
|
app := tview.NewApplication()
|
||||||
var currentFrame *tview.Frame
|
var currentFrame *tview.Frame
|
||||||
state := &UIState{
|
state := &UIState{
|
||||||
Page: "home",
|
Page: "home",
|
||||||
|
Error: "",
|
||||||
}
|
}
|
||||||
frame := AppUI(app, ¤tFrame, state)
|
frame := AppUI(app, ¤tFrame, state)
|
||||||
currentFrame = frame
|
currentFrame = frame
|
||||||
@@ -66,15 +83,9 @@ func main() {
|
|||||||
// Handle signals in a goroutine
|
// Handle signals in a goroutine
|
||||||
go func() {
|
go func() {
|
||||||
<-sigChan
|
<-sigChan
|
||||||
|
log.Println("Signal received, shutting down...")
|
||||||
// Cancel context to stop monitoring
|
// Cancel context to stop monitoring
|
||||||
cancel()
|
cancel()
|
||||||
// Disconnect device gracefully
|
|
||||||
if device.Connected {
|
|
||||||
log.Println("Disconnecting device...")
|
|
||||||
if err := device.Close(); err != nil {
|
|
||||||
log.Printf("Error disconnecting device: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Stop the application
|
// Stop the application
|
||||||
app.Stop()
|
app.Stop()
|
||||||
}()
|
}()
|
||||||
|
|||||||
+9
-12
@@ -1,10 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/fs"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io/fs"
|
||||||
"strings"
|
"strings"
|
||||||
"log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type PackageJSON struct {
|
type PackageJSON struct {
|
||||||
@@ -35,39 +34,37 @@ func loadPackageJSON(fsys fs.FS) (*PackageJSON, error) {
|
|||||||
|
|
||||||
func createCpkg(fsys fs.FS, pkgData *PackageJSON) (*cpkg, error) {
|
func createCpkg(fsys fs.FS, pkgData *PackageJSON) (*cpkg, error) {
|
||||||
pkg := NewCpkg(pkgData.Pkg)
|
pkg := NewCpkg(pkgData.Pkg)
|
||||||
|
|
||||||
// Walk through all directories recursively
|
// Walk through all directories recursively
|
||||||
err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
|
err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip directories themselves (we only want files)
|
// Skip directories themselves (we only want files)
|
||||||
if d.IsDir() {
|
if d.IsDir() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip certain files
|
// Skip certain files
|
||||||
fileName := d.Name()
|
fileName := d.Name()
|
||||||
if fileName == "debug.log" || strings.HasSuffix(fileName, ".cpkg") {
|
if fileName == "debug.log" || strings.HasSuffix(fileName, ".cpkg") {
|
||||||
log.Println("Skipping file:", path)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add file with full relative path
|
// Add file with full relative path
|
||||||
log.Println("Adding file:", path)
|
|
||||||
err = pkg.AddFile(fsys, path)
|
err = pkg.AddFile(fsys, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
success, err := pkg.Create()
|
success, err := pkg.Create()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -76,4 +73,4 @@ func createCpkg(fsys fs.FS, pkgData *PackageJSON) (*cpkg, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return pkg, nil
|
return pkg, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/gdamore/tcell/v2"
|
"github.com/gdamore/tcell/v2"
|
||||||
"github.com/rivo/tview"
|
"github.com/rivo/tview"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UIState struct {
|
type UIState struct {
|
||||||
Page string
|
Page string
|
||||||
|
Error string
|
||||||
|
Success string
|
||||||
}
|
}
|
||||||
|
|
||||||
func AppUI(app *tview.Application, currentFrame **tview.Frame, state *UIState) *tview.Frame {
|
func AppUI(app *tview.Application, currentFrame **tview.Frame, state *UIState) *tview.Frame {
|
||||||
@@ -18,6 +22,7 @@ func AppUI(app *tview.Application, currentFrame **tview.Frame, state *UIState) *
|
|||||||
app.SetRoot(newFrame, true)
|
app.SetRoot(newFrame, true)
|
||||||
})
|
})
|
||||||
list.AddItem("Upload to Cardputer", "Creates a package and uploads it to the connected Cardputer", 'u', nil)
|
list.AddItem("Upload to Cardputer", "Creates a package and uploads it to the connected Cardputer", 'u', nil)
|
||||||
|
list.AddItem("Live Refresh", "Monitors for changes and automatically uploads to the Cardputer (WIP)", 'l', nil)
|
||||||
frame := tview.NewFrame(list)
|
frame := tview.NewFrame(list)
|
||||||
frame.SetBorders(0, 0, 0, 0, 0, 0)
|
frame.SetBorders(0, 0, 0, 0, 0, 0)
|
||||||
frame.AddText("Parchment - v0.0.1", true, tview.AlignLeft, tcell.ColorWhite)
|
frame.AddText("Parchment - v0.0.1", true, tview.AlignLeft, tcell.ColorWhite)
|
||||||
@@ -26,9 +31,36 @@ func AppUI(app *tview.Application, currentFrame **tview.Frame, state *UIState) *
|
|||||||
return frame
|
return frame
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetError(state *UIState, text string) {
|
||||||
|
state.Success = ""
|
||||||
|
state.Error = text
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetSuccess(state *UIState, text string) {
|
||||||
|
state.Error = ""
|
||||||
|
state.Success = text
|
||||||
|
}
|
||||||
|
|
||||||
func PackageUI(app *tview.Application, currentFrame **tview.Frame, state *UIState) *tview.Frame {
|
func PackageUI(app *tview.Application, currentFrame **tview.Frame, state *UIState) *tview.Frame {
|
||||||
list := tview.NewList()
|
list := tview.NewList()
|
||||||
list.AddItem("Create Package", "Creates a .cpkg file in the running directory", 'c', nil)
|
list.AddItem("Create Package", "Creates a .cpkg file in the running directory", 'c', func() {
|
||||||
|
fsys := os.DirFS(".")
|
||||||
|
pkgData, err := loadPackageJSON(fsys)
|
||||||
|
if err != nil {
|
||||||
|
SetError(state, "Failed to load package.json")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if pkgData == nil {
|
||||||
|
SetError(state, "Failed to load package.json")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pkg, err := createCpkg(fsys, pkgData)
|
||||||
|
if err != nil {
|
||||||
|
SetError(state, err.Error())
|
||||||
|
} else {
|
||||||
|
SetSuccess(state, "Created file "+pkg.packageName+".cpkg")
|
||||||
|
}
|
||||||
|
})
|
||||||
list.AddItem("Unpack Package", "Unpacks a chosen .cpkg file into a subdirectory", 'u', nil)
|
list.AddItem("Unpack Package", "Unpacks a chosen .cpkg file into a subdirectory", 'u', nil)
|
||||||
list.AddItem("Back", "Go back to the home page", 'b', func() {
|
list.AddItem("Back", "Go back to the home page", 'b', func() {
|
||||||
newFrame := AppUI(app, currentFrame, state)
|
newFrame := AppUI(app, currentFrame, state)
|
||||||
@@ -52,6 +84,12 @@ func UpdateDeviceStatus(app *tview.Application, frame *tview.Frame, state *UISta
|
|||||||
case "package":
|
case "package":
|
||||||
frame.AddText("Package Tools", true, tview.AlignLeft, tcell.ColorWhite)
|
frame.AddText("Package Tools", true, tview.AlignLeft, tcell.ColorWhite)
|
||||||
}
|
}
|
||||||
|
if state.Error != "" {
|
||||||
|
frame.AddText(state.Error, false, tview.AlignRight, tcell.ColorRed)
|
||||||
|
}
|
||||||
|
if state.Success != "" {
|
||||||
|
frame.AddText(state.Success, false, tview.AlignRight, tcell.ColorGreen)
|
||||||
|
}
|
||||||
frame.AddText(status, false, tview.AlignLeft, color)
|
frame.AddText(status, false, tview.AlignLeft, color)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user