tunasync/worker/rsync_provider.go

98 lines
2.1 KiB
Go

package worker
import (
"errors"
"strings"
"time"
)
type rsyncConfig struct {
name string
rsyncCmd string
upstreamURL, password, excludeFile string
workingDir, logDir, logFile string
useIPv6 bool
interval time.Duration
}
// An RsyncProvider provides the implementation to rsync-based syncing jobs
type rsyncProvider struct {
baseProvider
rsyncConfig
options []string
}
func newRsyncProvider(c rsyncConfig) (*rsyncProvider, error) {
// TODO: check config options
if !strings.HasSuffix(c.upstreamURL, "/") {
return nil, errors.New("rsync upstream URL should ends with /")
}
provider := &rsyncProvider{
baseProvider: baseProvider{
name: c.name,
ctx: NewContext(),
interval: c.interval,
},
rsyncConfig: c,
}
if c.rsyncCmd == "" {
provider.rsyncCmd = "rsync"
}
options := []string{
"-aHvh", "--no-o", "--no-g", "--stats",
"--exclude", ".~tmp~/",
"--delete", "--delete-after", "--delay-updates",
"--safe-links", "--timeout=120", "--contimeout=120",
}
if c.useIPv6 {
options = append(options, "-6")
}
if c.excludeFile != "" {
options = append(options, "--exclude-from", c.excludeFile)
}
provider.options = options
provider.ctx.Set(_WorkingDirKey, c.workingDir)
provider.ctx.Set(_LogDirKey, c.logDir)
provider.ctx.Set(_LogFileKey, c.logFile)
return provider, nil
}
func (p *rsyncProvider) Upstream() string {
return p.upstreamURL
}
func (p *rsyncProvider) Run() error {
if err := p.Start(); err != nil {
return err
}
return p.Wait()
}
func (p *rsyncProvider) Start() error {
env := map[string]string{}
if p.password != "" {
env["RSYNC_PASSWORD"] = p.password
}
command := []string{p.rsyncCmd}
command = append(command, p.options...)
command = append(command, p.upstreamURL, p.WorkingDir())
p.cmd = newCmdJob(p, command, p.WorkingDir(), env)
if err := p.prepareLogFile(); err != nil {
return err
}
if err := p.cmd.Start(); err != nil {
return err
}
p.isRunning.Store(true)
return nil
}