From 0832f28dc73277c84996aca65a982ae7fb132a1b Mon Sep 17 00:00:00 2001
From: Michael Quigley <michael@quigley.com>
Date: Mon, 27 Nov 2023 15:44:38 -0500
Subject: [PATCH] framework start; webdav (#438)

---
 cmd/zrok/copyFrom.go | 42 ++++++++++---------------------
 util/sync/model.go   | 14 +++++++++++
 util/sync/webdav.go  | 59 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 86 insertions(+), 29 deletions(-)
 create mode 100644 util/sync/model.go
 create mode 100644 util/sync/webdav.go

diff --git a/cmd/zrok/copyFrom.go b/cmd/zrok/copyFrom.go
index ec2d2c44..58d1fce7 100644
--- a/cmd/zrok/copyFrom.go
+++ b/cmd/zrok/copyFrom.go
@@ -1,10 +1,9 @@
 package main
 
 import (
+	"github.com/openziti/zrok/util/sync"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
-	"github.com/studio-b12/gowebdav"
-	"path/filepath"
 )
 
 func init() {
@@ -27,34 +26,19 @@ func newCopyFromCommand() *copyFromCommand {
 }
 
 func (cmd *copyFromCommand) run(_ *cobra.Command, args []string) {
-	c := gowebdav.NewClient(args[0], "", "")
-	if err := c.Connect(); err != nil {
-		panic(err)
-	}
-	if err := cmd.recurseTree(c, ""); err != nil {
-		panic(err)
-	}
-}
-
-func (cmd *copyFromCommand) recurseTree(c *gowebdav.Client, path string) error {
-	files, err := c.ReadDir(path)
+	t, err := sync.NewWebDAVTarget(&sync.WebDAVTargetConfig{
+		URL:      args[0],
+		Username: "",
+		Password: "",
+	})
 	if err != nil {
-		return err
+		panic(err)
 	}
-	for _, f := range files {
-		sub := filepath.ToSlash(filepath.Join(path, f.Name()))
-		if f.IsDir() {
-			logrus.Infof("-> %v", sub)
-			if err := cmd.recurseTree(c, sub); err != nil {
-				return err
-			}
-		} else {
-			etag := "<etag>"
-			if v, ok := f.(gowebdav.File); ok {
-				etag = v.ETag()
-			}
-			logrus.Infof("++ %v (%v)", sub, etag)
-		}
+	tree, err := t.Inventory()
+	if err != nil {
+		panic(err)
+	}
+	for _, f := range tree {
+		logrus.Infof("-> %v [%v, %v, %v]", f.Path, f.Size, f.Modified, f.ETag)
 	}
-	return nil
 }
diff --git a/util/sync/model.go b/util/sync/model.go
new file mode 100644
index 00000000..948b86a8
--- /dev/null
+++ b/util/sync/model.go
@@ -0,0 +1,14 @@
+package sync
+
+import "time"
+
+type Object struct {
+	Path     string
+	Size     int64
+	Modified time.Time
+	ETag     string
+}
+
+type Target interface {
+	Inventory() ([]*Object, error)
+}
diff --git a/util/sync/webdav.go b/util/sync/webdav.go
new file mode 100644
index 00000000..ba9578d5
--- /dev/null
+++ b/util/sync/webdav.go
@@ -0,0 +1,59 @@
+package sync
+
+import (
+	"github.com/pkg/errors"
+	"github.com/studio-b12/gowebdav"
+	"path/filepath"
+)
+
+type WebDAVTargetConfig struct {
+	URL      string
+	Username string
+	Password string
+}
+
+type WebDAVTarget struct {
+	c *gowebdav.Client
+}
+
+func NewWebDAVTarget(cfg *WebDAVTargetConfig) (*WebDAVTarget, error) {
+	c := gowebdav.NewClient(cfg.URL, cfg.Username, cfg.Password)
+	if err := c.Connect(); err != nil {
+		return nil, errors.Wrap(err, "error connecting to webdav target")
+	}
+	return &WebDAVTarget{c: c}, nil
+}
+
+func (t *WebDAVTarget) Inventory() ([]*Object, error) {
+	tree, err := t.recurse("", nil)
+	if err != nil {
+		return nil, err
+	}
+	return tree, nil
+}
+
+func (t *WebDAVTarget) recurse(path string, tree []*Object) ([]*Object, error) {
+	files, err := t.c.ReadDir(path)
+	if err != nil {
+		return nil, err
+	}
+	for _, f := range files {
+		sub := filepath.ToSlash(filepath.Join(path, f.Name()))
+		if f.IsDir() {
+			tree, err = t.recurse(sub, tree)
+			if err != nil {
+				return nil, err
+			}
+		} else {
+			if v, ok := f.(gowebdav.File); ok {
+				tree = append(tree, &Object{
+					Path:     filepath.ToSlash(filepath.Join(path, f.Name())),
+					Size:     v.Size(),
+					Modified: v.ModTime(),
+					ETag:     v.ETag(),
+				})
+			}
+		}
+	}
+	return tree, nil
+}