mirror of
https://github.com/kopia/kopia.git
synced 2026-01-19 11:57:55 -05:00
Remove unused-parameter exclusion for `ctx` in revive linter. --------- Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com> Co-authored-by: Matthieu MOREL <matthieu.morel35@gmail.com>
126 lines
3.3 KiB
Go
126 lines
3.3 KiB
Go
package server
|
|
|
|
import (
|
|
"archive/zip"
|
|
"context"
|
|
"encoding/json"
|
|
"os"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/kopia/kopia/internal/serverapi"
|
|
"github.com/kopia/kopia/internal/uitask"
|
|
"github.com/kopia/kopia/snapshot/restore"
|
|
"github.com/kopia/kopia/snapshot/snapshotfs"
|
|
)
|
|
|
|
func restoreCounters(s restore.Stats) map[string]uitask.CounterValue {
|
|
return map[string]uitask.CounterValue{
|
|
"Restored Files": uitask.SimpleCounter(int64(s.RestoredFileCount)),
|
|
"Restored Directories": uitask.SimpleCounter(int64(s.RestoredDirCount)),
|
|
"Restored Symlinks": uitask.SimpleCounter(int64(s.RestoredSymlinkCount)),
|
|
"Restored Bytes": uitask.BytesCounter(s.RestoredTotalFileSize),
|
|
"Ignored Errors": uitask.SimpleCounter(int64(s.IgnoredErrorCount)),
|
|
"Skipped Files": uitask.SimpleCounter(int64(s.SkippedCount)),
|
|
"Skipped Bytes": uitask.BytesCounter(s.SkippedTotalFileSize),
|
|
}
|
|
}
|
|
|
|
func handleRestore(ctx context.Context, rc requestContext) (interface{}, *apiError) {
|
|
var req serverapi.RestoreRequest
|
|
|
|
if err := json.Unmarshal(rc.body, &req); err != nil {
|
|
return nil, requestError(serverapi.ErrorMalformedRequest, "malformed request body")
|
|
}
|
|
|
|
rep := rc.rep
|
|
|
|
if req.Root == "" {
|
|
return nil, requestError(serverapi.ErrorMalformedRequest, "root not specified")
|
|
}
|
|
|
|
rootEntry, err := snapshotfs.FilesystemEntryFromIDWithPath(ctx, rep, req.Root, false)
|
|
if err != nil {
|
|
return nil, requestError(serverapi.ErrorMalformedRequest, "invalid root entry")
|
|
}
|
|
|
|
var (
|
|
out restore.Output
|
|
description string
|
|
)
|
|
|
|
switch {
|
|
case req.Filesystem != nil:
|
|
if err := req.Filesystem.Init(ctx); err != nil {
|
|
return nil, internalServerError(err)
|
|
}
|
|
|
|
out = req.Filesystem
|
|
description = "Destination: " + req.Filesystem.TargetPath
|
|
|
|
case req.ZipFile != "":
|
|
f, err := os.Create(req.ZipFile)
|
|
if err != nil {
|
|
return nil, internalServerError(err)
|
|
}
|
|
|
|
if req.UncompressedZip {
|
|
out = restore.NewZipOutput(f, zip.Store)
|
|
description = "Uncompressed ZIP File: " + req.ZipFile
|
|
} else {
|
|
out = restore.NewZipOutput(f, zip.Deflate)
|
|
description = "ZIP File: " + req.ZipFile
|
|
}
|
|
|
|
case req.TarFile != "":
|
|
f, err := os.Create(req.TarFile)
|
|
if err != nil {
|
|
return nil, internalServerError(err)
|
|
}
|
|
|
|
out = restore.NewTarOutput(f)
|
|
description = "TAR File: " + req.TarFile
|
|
|
|
default:
|
|
return nil, requestError(serverapi.ErrorMalformedRequest, "output not specified")
|
|
}
|
|
|
|
taskIDChan := make(chan string)
|
|
|
|
// launch a goroutine that will continue the restore and can be observed in the Tasks UI.
|
|
|
|
//nolint:errcheck
|
|
go rc.srv.taskManager().Run(ctx, "Restore", description, func(ctx context.Context, ctrl uitask.Controller) error {
|
|
taskIDChan <- ctrl.CurrentTaskID()
|
|
|
|
opt := req.Options
|
|
|
|
opt.ProgressCallback = func(_ context.Context, s restore.Stats) {
|
|
ctrl.ReportCounters(restoreCounters(s))
|
|
}
|
|
|
|
cancelChan := make(chan struct{})
|
|
opt.Cancel = cancelChan
|
|
|
|
ctrl.OnCancel(func() {
|
|
close(opt.Cancel)
|
|
})
|
|
|
|
st, err := restore.Entry(ctx, rep, out, rootEntry, opt)
|
|
if err == nil {
|
|
ctrl.ReportCounters(restoreCounters(st))
|
|
}
|
|
|
|
return errors.Wrap(err, "error restoring")
|
|
})
|
|
|
|
taskID := <-taskIDChan
|
|
|
|
task, ok := rc.srv.taskManager().GetTask(taskID)
|
|
if !ok {
|
|
return nil, internalServerError(errors.New("task not found"))
|
|
}
|
|
|
|
return task, nil
|
|
}
|