Files
acp/job.go
2022-09-08 20:53:42 +08:00

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
}