2024-01-09 20:26:07 +01:00
|
|
|
package sync
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2024-01-10 17:44:06 +01:00
|
|
|
"github.com/openziti/zrok/drives/davClient"
|
2024-01-09 20:26:07 +01:00
|
|
|
"github.com/openziti/zrok/environment/env_core"
|
|
|
|
"github.com/openziti/zrok/sdk/golang/sdk"
|
2024-01-11 17:36:05 +01:00
|
|
|
"github.com/pkg/errors"
|
2024-01-09 20:26:07 +01:00
|
|
|
"io"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type ZrokTargetConfig struct {
|
2024-01-11 19:40:45 +01:00
|
|
|
URL *url.URL
|
|
|
|
Root env_core.Root
|
2024-01-09 20:26:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type ZrokTarget struct {
|
|
|
|
cfg *ZrokTargetConfig
|
2024-01-10 17:44:06 +01:00
|
|
|
dc *davClient.Client
|
2024-01-09 20:26:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type zrokDialContext struct {
|
|
|
|
root env_core.Root
|
|
|
|
}
|
|
|
|
|
|
|
|
func (zdc *zrokDialContext) Dial(_ context.Context, _, addr string) (net.Conn, error) {
|
|
|
|
share := strings.Split(addr, ":")[0]
|
|
|
|
return sdk.NewDialer(share, zdc.root)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewZrokTarget(cfg *ZrokTargetConfig) (*ZrokTarget, error) {
|
|
|
|
transport := http.DefaultTransport.(*http.Transport).Clone()
|
|
|
|
transport.DialContext = (&zrokDialContext{cfg.Root}).Dial
|
|
|
|
transport.TLSClientConfig.InsecureSkipVerify = true
|
|
|
|
httpUrl := strings.Replace(cfg.URL.String(), "zrok:", "http:", 1)
|
2024-01-10 17:44:06 +01:00
|
|
|
dc, err := davClient.NewClient(&http.Client{Transport: transport}, httpUrl)
|
2024-01-09 20:26:07 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &ZrokTarget{cfg: cfg, dc: dc}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *ZrokTarget) Inventory() ([]*Object, error) {
|
2024-01-10 19:38:35 +01:00
|
|
|
rootFi, err := t.dc.Stat(context.Background(), t.cfg.URL.Path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !rootFi.IsDir {
|
2024-01-10 19:55:07 +01:00
|
|
|
base := filepath.Base(t.cfg.URL.Path)
|
|
|
|
t.cfg.URL.Path = filepath.Dir(t.cfg.URL.Path)
|
2024-01-10 19:38:35 +01:00
|
|
|
return []*Object{{
|
2024-01-10 19:55:07 +01:00
|
|
|
Path: "/" + base,
|
2024-01-10 19:38:35 +01:00
|
|
|
IsDir: false,
|
|
|
|
Size: rootFi.Size,
|
|
|
|
Modified: rootFi.ModTime,
|
|
|
|
}}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
fis, err := t.dc.Readdir(context.Background(), t.cfg.URL.Path, true)
|
2024-01-09 20:26:07 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var objects []*Object
|
|
|
|
for _, fi := range fis {
|
|
|
|
if fi.Path != "/" {
|
|
|
|
objects = append(objects, &Object{
|
|
|
|
Path: fi.Path,
|
|
|
|
IsDir: fi.IsDir,
|
|
|
|
Size: fi.Size,
|
|
|
|
Modified: fi.ModTime,
|
|
|
|
ETag: fi.ETag,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return objects, nil
|
|
|
|
}
|
|
|
|
|
2024-01-10 20:35:27 +01:00
|
|
|
func (t *ZrokTarget) Dir(path string) ([]*Object, error) {
|
|
|
|
fis, err := t.dc.Readdir(context.Background(), t.cfg.URL.Path, false)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var objects []*Object
|
|
|
|
for _, fi := range fis {
|
2024-01-11 17:44:17 +01:00
|
|
|
if fi.Path != "/" && fi.Path != t.cfg.URL.Path+"/" {
|
2024-01-10 20:35:27 +01:00
|
|
|
objects = append(objects, &Object{
|
|
|
|
Path: filepath.Base(fi.Path),
|
|
|
|
IsDir: fi.IsDir,
|
|
|
|
Size: fi.Size,
|
|
|
|
Modified: fi.ModTime,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return objects, nil
|
|
|
|
}
|
|
|
|
|
2024-01-09 20:26:07 +01:00
|
|
|
func (t *ZrokTarget) Mkdir(path string) error {
|
2024-01-11 17:36:05 +01:00
|
|
|
fi, err := t.dc.Stat(context.Background(), filepath.Join(t.cfg.URL.Path, path))
|
|
|
|
if err == nil {
|
|
|
|
if fi.IsDir {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return errors.Errorf("'%v' already exists; not directory", path)
|
|
|
|
}
|
2024-01-09 20:26:07 +01:00
|
|
|
return t.dc.Mkdir(context.Background(), filepath.Join(t.cfg.URL.Path, path))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *ZrokTarget) ReadStream(path string) (io.ReadCloser, error) {
|
|
|
|
return t.dc.Open(context.Background(), filepath.Join(t.cfg.URL.Path, path))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *ZrokTarget) WriteStream(path string, rs io.Reader, _ os.FileMode) error {
|
|
|
|
ws, err := t.dc.Create(context.Background(), filepath.Join(t.cfg.URL.Path, path))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer func() { _ = ws.Close() }()
|
|
|
|
_, err = io.Copy(ws, rs)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-01-16 19:54:01 +01:00
|
|
|
func (t *ZrokTarget) WriteStreamWithModTime(path string, rs io.Reader, _ os.FileMode, modTime time.Time) error {
|
|
|
|
ws, err := t.dc.CreateWithModTime(context.Background(), filepath.Join(t.cfg.URL.Path, path), modTime)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer func() { _ = ws.Close() }()
|
|
|
|
_, err = io.Copy(ws, rs)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-01-11 19:19:20 +01:00
|
|
|
func (t *ZrokTarget) Move(src, dest string) error {
|
|
|
|
return t.dc.MoveAll(context.Background(), filepath.Join(t.cfg.URL.Path, src), dest, true)
|
|
|
|
}
|
|
|
|
|
2024-01-11 18:11:21 +01:00
|
|
|
func (t *ZrokTarget) Rm(path string) error {
|
|
|
|
return t.dc.RemoveAll(context.Background(), filepath.Join(t.cfg.URL.Path, path))
|
|
|
|
}
|
|
|
|
|
2024-01-09 20:26:07 +01:00
|
|
|
func (t *ZrokTarget) SetModificationTime(path string, mtime time.Time) error {
|
|
|
|
return t.dc.Touch(context.Background(), filepath.Join(t.cfg.URL.Path, path), mtime)
|
|
|
|
}
|