diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..456d79e --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +GOPATH=$(shell go env GOPATH) + +.PHONY: test +test: + @echo "==> Running tests" + go test -v ./... diff --git a/main.go b/main.go index 5408054..12d55c1 100644 --- a/main.go +++ b/main.go @@ -1,43 +1,43 @@ package core import ( - "bytes" - "io" - "log" - "os" + "bytes" + "io" + "log" + "os" - "github.com/ulikunitz/xz" - // "syscall/js" + "github.com/ulikunitz/xz" + // "syscall/js" ) func Compress() { - const text = "The quick brown fox jumps over the lazy dog.\n" - var buf bytes.Buffer - // compress text - w, err := xz.NewWriter(&buf) - if err != nil { - log.Fatalf("xz.NewWriter error %s", err) - } - if _, err := io.WriteString(w, text); err != nil { - log.Fatalf("WriteString error %s", err) - } - if err := w.Close(); err != nil { - log.Fatalf("w.Close error %s", err) - } - // decompress buffer and write output to stdout - r, err := xz.NewReader(&buf) - if err != nil { - log.Fatalf("NewReader error %s", err) - } - if _, err = io.Copy(os.Stdout, r); err != nil { - log.Fatalf("io.Copy error %s", err) - } + const text = "The quick brown fox jumps over the lazy dog.\n" + var buf bytes.Buffer + // compress text + w, err := xz.NewWriter(&buf) + if err != nil { + log.Fatalf("xz.NewWriter error %s", err) + } + if _, err := io.WriteString(w, text); err != nil { + log.Fatalf("WriteString error %s", err) + } + if err := w.Close(); err != nil { + log.Fatalf("w.Close error %s", err) + } + // decompress buffer and write output to stdout + r, err := xz.NewReader(&buf) + if err != nil { + log.Fatalf("NewReader error %s", err) + } + if _, err = io.Copy(os.Stdout, r); err != nil { + log.Fatalf("io.Copy error %s", err) + } } // var c = make(chan struct{}) // func main() { - + // js.Global().Set("myexport", "juas") // <-c -// } \ No newline at end of file +// } diff --git a/repository/filesystem.go b/repository/filesystem.go new file mode 100644 index 0000000..46b4980 --- /dev/null +++ b/repository/filesystem.go @@ -0,0 +1,93 @@ +package repository + +import ( + "fmt" + "io" + "io/ioutil" + "log" + "os" + "path" + + cid "github.com/ipfs/go-cid" + mbase "github.com/multiformats/go-multibase" + mh "github.com/multiformats/go-multihash" +) + +// FileSystemRepository is a repository implementation which uses a +// file system to gets and store the data +type FileSystemRepository struct { + FileMode os.FileMode + Directory string +} + +// NewFileSystemRepository constructor +func NewFileSystemRepository(dir string) (*FileSystemRepository, error) { + if err := makeDirectoryIfDoesntExist(dir); err != nil { + return nil, fmt.Errorf("Failed to initialize repository the directory %s can't be created", dir) + } + + return &FileSystemRepository{ + FileMode: 0644, + Directory: dir, + }, nil +} + +// Add create resource and returns a unique identifier +func (repo *FileSystemRepository) Add(reader io.Reader) (string, error) { + + hash := cid.Prefix{ + Version: 1, + Codec: cid.Raw, + MhType: mh.SHA2_256, + MhLength: -1, // default length + } + + buf, err := ioutil.ReadAll(reader) + if err != nil { + return "", err + } + + cid, err := hash.Sum(buf) + if err != nil { + return "", err + } + + scid, err := cid.StringOfBase(mbase.Base58BTC) + if err != nil { + return "", err + } + + fullpath := getFullpathFilename(repo.Directory, scid) + if err := ioutil.WriteFile(fullpath, buf, repo.FileMode); err != nil { + return "", err + } + + return scid, nil +} + +func (repo *FileSystemRepository) Get(scid string) (io.Reader, error) { + return os.Open(getFullpathFilename(repo.Directory, scid)) +} + +func (repo *FileSystemRepository) Remove(scid string) error { + return os.Remove(getFullpathFilename(repo.Directory, scid)) +} + +func getFullpathFilename(dir string, scid string) string { + return path.Join(dir, scid) +} + +// Checks if directory exists and if not then +// create it recusrsively like mkdir -p +func makeDirectoryIfDoesntExist(dir string) error { + _, err := os.Stat(dir) + if err == nil { + log.Printf("FileSystemRepository the directory \"%s\" already exists ignoring creation", dir) + return nil + } + err = os.MkdirAll(dir, os.ModePerm) + if err == nil { + log.Printf("FileSystemRepository root directory created! %s", dir) + } + return err +} diff --git a/repository/filesystem_test.go b/repository/filesystem_test.go new file mode 100644 index 0000000..c3a187e --- /dev/null +++ b/repository/filesystem_test.go @@ -0,0 +1,74 @@ +package repository + +import ( + "bufio" + "bytes" + "fmt" + "io/ioutil" + "os" + "path" + "strings" + "testing" + + "github.com/lot-sh/core/types" +) + +var ( + repo types.Repository + directory = path.Join(os.TempDir(), "lotsh/lib") + filecontent = "This is a test" + hash = "zb2rhk5zU8kdMPiPKgdxjhXTxs7KBxaXFqDhK2sBr5xQckX5f" + err error +) + +func TestErrorWhenInitialize(t *testing.T) { + prohibitedDir := "/test" + repo, err = NewFileSystemRepository(prohibitedDir) + if err == nil { + t.Errorf("Error must be raised but got nil") + } + actual := err.Error() + expected := fmt.Sprintf("Failed to initialize repository the directory %s can't be created", prohibitedDir) + if !strings.Contains(actual, expected) { + t.Errorf("Missmatch content \n-> Actual: %s \n-> Expected: %s", actual, expected) + } +} + +func TestInitializeWithoutErrors(t *testing.T) { + repo, err = NewFileSystemRepository(directory) + if err != nil { + t.Error(err) + } +} + +func TestRepositoryAdd(t *testing.T) { + buf := bytes.NewBufferString(filecontent) + actual, err := repo.Add(bufio.NewReader(buf)) + expected := hash + if err != nil { + t.Fatalf("Test failed in create resource; %s\n", err) + } + + if !strings.Contains(string(actual), expected) { + t.Errorf("Missmatch content \n-> Actual: %s \n-> Expected: %s", actual, expected) + } +} + +func TestRepositoryGet(t *testing.T) { + reader, err := repo.Get(hash) + actual, err := ioutil.ReadAll(reader) + expected := filecontent + if err != nil { + t.Logf("Test failed in get resource; %s\n", err) + } + + if !strings.Contains(string(actual), expected) { + t.Errorf("Missmatch content \n-> Actual: %s \n-> Expected: %s", actual, expected) + } +} + +func TestRepositoryRemove(t *testing.T) { + if err := repo.Remove(hash); err != nil { + t.Fatalf("Test failed when remove resource: %s\n", err) + } +} diff --git a/types/repository.go b/types/repository.go new file mode 100644 index 0000000..daca294 --- /dev/null +++ b/types/repository.go @@ -0,0 +1,15 @@ +package types + +import ( + "io" +) + +//Repository provides access to the resource storage +type Repository interface { + // Get io.Reader from the resource storage by CID + Get(scid string) (io.Reader, error) + // Remove and existing resource using CID + Remove(scid string) error + // Add a resource with the CID as name generated from the content of io.Reader + Add(reader io.Reader) (string, error) +}