mirror of
https://github.com/samuelncui/acp.git
synced 2026-01-03 10:05:16 +00:00
155 lines
2.7 KiB
Go
155 lines
2.7 KiB
Go
package acp
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/abc950309/acp/mmap"
|
|
)
|
|
|
|
type jobType uint8
|
|
|
|
const (
|
|
jobTypeNormal = jobType(iota)
|
|
jobTypeDir
|
|
)
|
|
|
|
type jobStatus uint8
|
|
|
|
const (
|
|
jobStatusPending = jobStatus(iota)
|
|
jobStatusPreparing
|
|
jobStatusCopying
|
|
jobStatusFinishing
|
|
jobStatusFinished
|
|
)
|
|
|
|
var (
|
|
statusMapping = map[jobStatus]string{
|
|
jobStatusPending: "pending",
|
|
jobStatusPreparing: "preparing",
|
|
jobStatusCopying: "copying",
|
|
jobStatusFinishing: "finishing",
|
|
jobStatusFinished: "finished",
|
|
}
|
|
)
|
|
|
|
type baseJob struct {
|
|
parent *baseJob
|
|
source *source
|
|
typ jobType
|
|
|
|
name string // base name of the file
|
|
size int64 // length in bytes for regular files; system-dependent for others
|
|
mode os.FileMode // file mode bits
|
|
modTime time.Time // modification time
|
|
|
|
lock sync.Mutex
|
|
writeTime time.Time
|
|
status jobStatus
|
|
children map[*baseJob]struct{}
|
|
|
|
successTargets []string
|
|
failedTargets map[string]error
|
|
hash []byte
|
|
|
|
// utils
|
|
comparableRelativePath string
|
|
}
|
|
|
|
func newJobFromFileInfo(parent *baseJob, source *source, info os.FileInfo) (*baseJob, error) {
|
|
job := &baseJob{
|
|
parent: parent,
|
|
source: source,
|
|
|
|
name: info.Name(),
|
|
size: info.Size(),
|
|
mode: info.Mode(),
|
|
modTime: info.ModTime(),
|
|
|
|
comparableRelativePath: strings.ReplaceAll(source.relativePath, "/", "\x00"),
|
|
}
|
|
if job.mode.IsDir() {
|
|
job.typ = jobTypeDir
|
|
}
|
|
|
|
return job, nil
|
|
}
|
|
|
|
func (j *baseJob) setStatus(s jobStatus) {
|
|
j.lock.Lock()
|
|
defer j.lock.Unlock()
|
|
j.status = s
|
|
|
|
if s == jobStatusCopying {
|
|
j.writeTime = time.Now()
|
|
}
|
|
}
|
|
|
|
func (j *baseJob) setHash(h []byte) {
|
|
j.lock.Lock()
|
|
defer j.lock.Unlock()
|
|
j.hash = h
|
|
}
|
|
|
|
func (j *baseJob) done(child *baseJob) int {
|
|
if j.typ == jobTypeNormal {
|
|
return 0
|
|
}
|
|
|
|
j.lock.Lock()
|
|
defer j.lock.Unlock()
|
|
|
|
delete(j.children, child)
|
|
return len(j.children)
|
|
}
|
|
|
|
func (j *baseJob) succes(path string) {
|
|
j.lock.Lock()
|
|
defer j.lock.Unlock()
|
|
j.successTargets = append(j.successTargets, path)
|
|
}
|
|
|
|
func (j *baseJob) fail(path string, err error) {
|
|
j.lock.Lock()
|
|
defer j.lock.Unlock()
|
|
|
|
if j.failedTargets == nil {
|
|
j.failedTargets = make(map[string]error, 1)
|
|
}
|
|
j.failedTargets[path] = err
|
|
}
|
|
|
|
func (j *baseJob) report() *File {
|
|
j.lock.Lock()
|
|
defer j.lock.Unlock()
|
|
|
|
fails := make(map[string]string, len(j.failedTargets))
|
|
for n, e := range j.failedTargets {
|
|
fails[n] = e.Error()
|
|
}
|
|
|
|
return &File{
|
|
Source: j.source.path(),
|
|
RelativePath: j.source.relativePath,
|
|
|
|
Status: statusMapping[j.status],
|
|
SuccessTargets: j.successTargets,
|
|
FailTargets: fails,
|
|
|
|
Size: j.size,
|
|
Mode: j.mode,
|
|
ModTime: j.modTime,
|
|
WriteTime: j.writeTime,
|
|
SHA256: hex.EncodeToString(j.hash),
|
|
}
|
|
}
|
|
|
|
type writeJob struct {
|
|
*baseJob
|
|
src *mmap.ReaderAt
|
|
}
|