402 lines
9.2 KiB
Go
402 lines
9.2 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
|
|
evdev "github.com/gvalkov/golang-evdev"
|
|
"github.com/marcellmars/lsblk"
|
|
)
|
|
|
|
var (
|
|
copyStatus = false
|
|
cancelCopy = false
|
|
)
|
|
|
|
func check(e error) {
|
|
if e != nil {
|
|
fmt.Println(fmt.Errorf("FROM CHECK: %w", e))
|
|
panic(e)
|
|
}
|
|
return
|
|
}
|
|
|
|
func recoverFromError() {
|
|
if r := recover(); r != nil {
|
|
fmt.Println("MYERROR:", r)
|
|
panic(r)
|
|
}
|
|
}
|
|
|
|
//_START: CopyToDisk
|
|
|
|
type Files struct {
|
|
Files []PathTotalSize
|
|
}
|
|
|
|
type PathTotalSize struct {
|
|
IsDir bool
|
|
Path string
|
|
FileSize int64
|
|
FileSizeHumanReadable string
|
|
TotalSize int64
|
|
TotalSizeHumanReadable string
|
|
}
|
|
|
|
func byteCountSI(b int64) string {
|
|
const unit = 1000
|
|
if b < unit {
|
|
return fmt.Sprintf("%dB", b)
|
|
}
|
|
div, exp := int64(unit), 0
|
|
for n := b / unit; n >= unit; n /= unit {
|
|
div *= unit
|
|
exp++
|
|
}
|
|
return fmt.Sprintf("%.3f%cB",
|
|
float64(b)/float64(div), "kMGTPE"[exp])
|
|
}
|
|
|
|
func copyToDisk(p string, waitingLoop chan string, cancelCopy chan bool) {
|
|
var totalSize int64
|
|
var ps Files
|
|
var bufSize int64
|
|
fmt.Println("COPY STARTED...")
|
|
s := time.Now()
|
|
// srcBaseDir := "/dev/shm/src/"
|
|
// srcBaseDir := "/home/m/CalibreLibraries/"
|
|
srcBaseDir := "/home/pi/"
|
|
srcDir := "MemoryOfTheWorld4Orsimanirana/"
|
|
// srcDir := "PirateCareCollection/"
|
|
destBaseDir := "/mnt/MOTW0/"
|
|
// destBaseDir := "/dev/shm/dest/"
|
|
//
|
|
ps.Files = append(
|
|
ps.Files,
|
|
PathTotalSize{
|
|
IsDir: true,
|
|
Path: srcBaseDir + srcDir,
|
|
FileSize: 0,
|
|
FileSizeHumanReadable: "0Kb",
|
|
TotalSize: 0,
|
|
TotalSizeHumanReadable: "0Kb",
|
|
})
|
|
|
|
ps.Files = append(
|
|
ps.Files,
|
|
PathTotalSize{
|
|
IsDir: false,
|
|
Path: srcBaseDir + srcDir + "_README_.txt",
|
|
FileSize: 4,
|
|
FileSizeHumanReadable: "4Kb",
|
|
TotalSize: 4,
|
|
TotalSizeHumanReadable: "4Kb",
|
|
})
|
|
|
|
ps.Files = append(
|
|
ps.Files,
|
|
PathTotalSize{
|
|
IsDir: false,
|
|
Path: srcBaseDir + srcDir + "BROWSE_LIBRARY.html",
|
|
FileSize: 4,
|
|
FileSizeHumanReadable: "4Kb",
|
|
TotalSize: 4,
|
|
TotalSizeHumanReadable: "4Kb",
|
|
})
|
|
|
|
err := filepath.Walk(filepath.Join(srcBaseDir, srcDir+"static"), func(path string, info os.FileInfo, err error) error {
|
|
check(err)
|
|
totalSize = totalSize + info.Size()
|
|
ps.Files = append(
|
|
ps.Files,
|
|
PathTotalSize{
|
|
IsDir: info.IsDir(),
|
|
Path: path,
|
|
FileSize: info.Size(),
|
|
FileSizeHumanReadable: byteCountSI(info.Size()),
|
|
TotalSize: totalSize,
|
|
TotalSizeHumanReadable: byteCountSI(totalSize),
|
|
})
|
|
return nil
|
|
})
|
|
check(err)
|
|
|
|
err = filepath.Walk(filepath.Join(srcBaseDir, srcDir), func(path string, info os.FileInfo, err error) error {
|
|
check(err)
|
|
totalSize = totalSize + info.Size()
|
|
if path == srcBaseDir+srcDir+"static" || path == srcBaseDir+srcDir+"_README_.html" || path == srcBaseDir+srcDir+"BROWSE_LIBRARY.html" {
|
|
return nil
|
|
}
|
|
ps.Files = append(
|
|
ps.Files,
|
|
PathTotalSize{
|
|
IsDir: info.IsDir(),
|
|
Path: path,
|
|
FileSize: info.Size(),
|
|
FileSizeHumanReadable: byteCountSI(info.Size()),
|
|
TotalSize: totalSize,
|
|
TotalSizeHumanReadable: byteCountSI(totalSize),
|
|
})
|
|
return nil
|
|
})
|
|
check(err)
|
|
|
|
copyStatus = true
|
|
availableDisk := lsblk.USBMountedPartitionAvailableSpace("/mnt/MOTW0")
|
|
for _, file := range ps.Files {
|
|
setLedLight(p, true)
|
|
|
|
// sf := time.Now()
|
|
destPath := filepath.Join(destBaseDir, strings.ReplaceAll(file.Path, srcBaseDir, ""))
|
|
if file.IsDir {
|
|
err := os.MkdirAll(destPath, os.ModePerm)
|
|
check(err)
|
|
continue
|
|
}
|
|
|
|
if availableDisk > 0 && (file.TotalSize > availableDisk) {
|
|
fmt.Println("NOT ENOUGH OF DISK SPACE:", "Last file copied:", file.Path)
|
|
waitingLoop <- "finishing"
|
|
return
|
|
}
|
|
|
|
// fmt.Printf("_%s_", file.FileSizeHumanReadable)
|
|
inFile, err := os.Open(file.Path)
|
|
check(err)
|
|
|
|
outFile, err := os.Create(destPath)
|
|
check(err)
|
|
|
|
reader := bufio.NewReader(inFile)
|
|
writer := bufio.NewWriter(outFile)
|
|
bufSize = 512 * 2 * 16
|
|
buf := make([]byte, 0, bufSize)
|
|
|
|
for {
|
|
n, err := io.ReadFull(reader, buf[:cap(buf)])
|
|
buf = buf[:n]
|
|
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
|
|
if err != io.ErrUnexpectedEOF {
|
|
check(err)
|
|
}
|
|
}
|
|
writer.Write(buf)
|
|
writer.Flush()
|
|
// outFile.Sync()
|
|
}
|
|
outFile.Sync()
|
|
outFile.Close()
|
|
inFile.Close()
|
|
select {
|
|
case cc := <-cancelCopy:
|
|
if cc {
|
|
fmt.Println("CANCEL VIA KEYBOARD:", "Last file copied:", file.Path)
|
|
setLedLight(p, true)
|
|
waitingLoop <- "finishing"
|
|
return
|
|
}
|
|
default:
|
|
}
|
|
setLedLight(p, false)
|
|
}
|
|
|
|
setLedLight(p, true)
|
|
lastFile := ps.Files[len(ps.Files)-1]
|
|
fmt.Println(lastFile.Path, lastFile.TotalSizeHumanReadable)
|
|
e := time.Now()
|
|
fmt.Printf("TIME: %v\n", e.Sub(s))
|
|
fmt.Println("BUFFER SIZE:", byteCountSI(bufSize))
|
|
copyStatus = false
|
|
waitingLoop <- "finishing"
|
|
}
|
|
|
|
//_END: CopyToDisk
|
|
|
|
//_START: NumKey & LED
|
|
|
|
func setLedLight(p string, state bool) {
|
|
d, err := os.Create(p)
|
|
check(err)
|
|
defer d.Close()
|
|
var led evdev.InputEvent
|
|
var bb bytes.Buffer
|
|
var time syscall.Timeval
|
|
err = syscall.Gettimeofday(&time)
|
|
check(err)
|
|
led.Time = time
|
|
led.Type = evdev.EV_LED
|
|
led.Code = evdev.LED_NUML
|
|
if state {
|
|
led.Value = 1
|
|
} else {
|
|
led.Value = 0
|
|
}
|
|
|
|
binary.Write(&bb, binary.LittleEndian, led)
|
|
d.Write(bb.Bytes())
|
|
}
|
|
|
|
func grebIt(greb chan *evdev.InputEvent, device *evdev.InputDevice) {
|
|
for {
|
|
i, _ := device.ReadOne()
|
|
greb <- i
|
|
}
|
|
}
|
|
|
|
//_END: NumKey & LED
|
|
|
|
//_START: Initial unmounting
|
|
func umountUSBDisk() bool {
|
|
for range [10]int{} {
|
|
if lsblk.USBMountpointed("/mnt/MOTW0") {
|
|
fmt.Println("Initial pass unmount MOTW0.")
|
|
_, err := exec.Command("umount", "/mnt/MOTW0").Output()
|
|
check(err)
|
|
} else {
|
|
return true
|
|
}
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
return false
|
|
}
|
|
|
|
//_END: Initial unmounting
|
|
|
|
//_START: Mounting USB disk
|
|
func mountUSBDisk(waitingLoop chan string) bool {
|
|
largestNotMounted := lsblk.USBNotMountedPartitionOfLargestSize()
|
|
if largestNotMounted.Name != "" {
|
|
|
|
fmt.Println("mounting usb disk...", largestNotMounted.Name, largestNotMounted.Mountpoint, largestNotMounted.Fstype, largestNotMounted.Size.HumanReadable)
|
|
// _, err := exec.Command("mount", "-t", largestNotMounted.Fstype, largestNotMounted.Name, "/mnt/MOTW0").Output()
|
|
_, err := exec.Command("mount", largestNotMounted.Name, "/mnt/MOTW0").Output()
|
|
check(err)
|
|
fmt.Println("just mounted:", largestNotMounted.Name, largestNotMounted.Mountpoint, largestNotMounted.Fstype, largestNotMounted.Size.HumanReadable, "available space:", lsblk.USBMountedPartitionAvailableSpace("/mnt/MOTW0"))
|
|
fmt.Printf("^")
|
|
return true
|
|
}
|
|
|
|
if lsblk.USBMountpointed("/mnt/MOTW0") {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
//_END: Mounting USB disk
|
|
|
|
func main() {
|
|
defer recoverFromError()
|
|
//_START: NumKey & LED
|
|
devices, _ := evdev.ListInputDevices()
|
|
myNumKeyboard := []string{}
|
|
for _, d := range devices {
|
|
// fmt.Println("name: ", d.Name, "phys: ", d.Phys, "file.name: ", d.File.Name(), "bustype: ", d.Bustype, "vendor: ", d.Vendor, "product: ", d.Product, "version: ", d.Version)
|
|
if d.Vendor == 1241 && d.Product == 4611 {
|
|
myNumKeyboard = append(myNumKeyboard, d.File.Name())
|
|
// fmt.Println("myNumKeyboard:", myNumKeyboard)
|
|
// break
|
|
}
|
|
}
|
|
sort.Strings(myNumKeyboard)
|
|
if len(myNumKeyboard) > 0 {
|
|
fmt.Println("Good! Keyboard attached:", myNumKeyboard)
|
|
setLedLight(myNumKeyboard[0], false)
|
|
} else {
|
|
os.Exit(1)
|
|
}
|
|
|
|
device, _ := evdev.Open(myNumKeyboard[0])
|
|
// device.Grab()
|
|
|
|
initialLoop := true
|
|
greb := make(chan *evdev.InputEvent, 1)
|
|
go grebIt(greb, device)
|
|
//_END: NumKey & LED
|
|
|
|
//_START waitingLoop
|
|
waitingLoop := make(chan string, 1024*100)
|
|
waitingLoop <- "initial"
|
|
//_END copyLoop
|
|
|
|
cancelCopy := make(chan bool, 10)
|
|
|
|
// go copyToDisk(myNumKeyboard[0], waitingLoop, greb)
|
|
|
|
for {
|
|
select {
|
|
case ev := <-greb:
|
|
if ev.Type == evdev.EV_KEY && ev.Value == 0 {
|
|
fmt.Println(ev.String())
|
|
if copyStatus {
|
|
cancelCopy <- true
|
|
}
|
|
if initialLoop {
|
|
initialLoop = false
|
|
}
|
|
// } else if ev.Type == evdev.EV_LED {
|
|
// fmt.Println("LED:", ev.String())
|
|
}
|
|
default:
|
|
}
|
|
|
|
select {
|
|
case wl := <-waitingLoop:
|
|
if wl == "initial" {
|
|
fmt.Println("waitingLoop state:", wl)
|
|
if !umountUSBDisk() {
|
|
fmt.Println("Need a hard reset.")
|
|
os.Exit(1)
|
|
} else {
|
|
waitingLoop <- "mounting"
|
|
}
|
|
} else if wl == "mounting" {
|
|
if mountUSBDisk(waitingLoop) {
|
|
waitingLoop <- "copying"
|
|
} else {
|
|
waitingLoop <- "mounting"
|
|
}
|
|
} else if wl == "copying" {
|
|
fmt.Println("waitingLoop state:", wl)
|
|
go copyToDisk(myNumKeyboard[0], waitingLoop, cancelCopy)
|
|
} else if wl == "finishing" {
|
|
fmt.Println("waitingLoop state:", wl)
|
|
if !umountUSBDisk() {
|
|
fmt.Println("Need a hard reset.")
|
|
os.Exit(1)
|
|
} else {
|
|
waitingLoop <- "ejecting"
|
|
setLedLight(myNumKeyboard[0], false)
|
|
}
|
|
} else if wl == "ejecting" {
|
|
fmt.Println("waitingLoop state:", wl)
|
|
for {
|
|
if lsblk.NoUSBDisksAttached() {
|
|
waitingLoop <- "initial"
|
|
break
|
|
} else {
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
}
|
|
time.Sleep(10 * time.Millisecond)
|
|
}
|
|
}
|