diff --git a/hyphae/empty_hypha.go b/hyphae/empty_hypha.go new file mode 100644 index 0000000..c4a958b --- /dev/null +++ b/hyphae/empty_hypha.go @@ -0,0 +1,36 @@ +package hyphae + +import "sync" + +type EmptyHypha struct { + sync.RWMutex + + canonicalName string +} + +func (e *EmptyHypha) CanonicalName() string { + return e.canonicalName +} + +func (e *EmptyHypha) Kind() HyphaKind { + return HyphaEmpty +} + +func (e *EmptyHypha) DoesExist() bool { + return false +} + +func (e *EmptyHypha) HasTextPart() bool { + return false +} + +func (e *EmptyHypha) TextPartPath() string { + return "" +} + +// NewEmptyHypha returns an empty hypha struct with given name. +func NewEmptyHypha(hyphaName string) *EmptyHypha { + return &EmptyHypha{ + canonicalName: hyphaName, + } +} diff --git a/hyphae/interface.go b/hyphae/interface.go index b704b44..edb2d7c 100644 --- a/hyphae/interface.go +++ b/hyphae/interface.go @@ -1,6 +1,26 @@ package hyphae -import "sync" +import ( + "regexp" + "strings" + "sync" +) + +// HyphaPattern is a pattern which all hyphae names must match. +var HyphaPattern = regexp.MustCompile(`[^?!:#@><*|"'&%{}]+`) + +// IsValidName checks for invalid characters and path traversals. +func IsValidName(hyphaName string) bool { + if !HyphaPattern.MatchString(hyphaName) { + return false + } + for _, segment := range strings.Split(hyphaName, "/") { + if segment == ".git" || segment == ".." { + return false + } + } + return true +} type HyphaKind int @@ -42,3 +62,43 @@ func RenameHyphaTo(h Hypher, newName string) { byNamesMutex.Unlock() h.Unlock() } + +// insert inserts the hypha into the storage. A previous record is used if possible. Count incrementation is done if needed. +func insert(h Hypher) (madeNewRecord bool) { + hp, recorded := byNames[h.CanonicalName()] + if recorded { + hp.(*MediaHypha).mergeIn(h) + } else { + storeHypha(h) + incrementCount() + } + + return !recorded +} + +// InsertIfNew checks whether hypha exists and returns `true` if it didn't and has been created. +func InsertIfNew(h Hypher) (madeNewRecord bool) { + if h.DoesExist() { + return false + } + return insert(h) +} + +func storeHypha(h Hypher) { + byNamesMutex.Lock() + byNames[h.CanonicalName()] = h + byNamesMutex.Unlock() + + h.Lock() + h.(*MediaHypha).Exists = true + h.Unlock() +} + +// ByName returns a hypha by name. It may have been recorded to the storage. +func ByName(hyphaName string) (h Hypher) { + h, recorded := byNames[hyphaName] + if recorded { + return h + } + return NewEmptyHypha(hyphaName) +} diff --git a/hyphae/iterators.go b/hyphae/iterators.go index f2a0989..15e7b22 100644 --- a/hyphae/iterators.go +++ b/hyphae/iterators.go @@ -5,8 +5,12 @@ package hyphae import ( "sort" "strings" + "sync" ) +var byNames = make(map[string]Hypher) +var byNamesMutex = sync.Mutex{} + // YieldExistingHyphae iterates over all hyphae and yields all existing ones. func YieldExistingHyphae() chan Hypher { ch := make(chan Hypher) diff --git a/hyphae/hyphae.go b/hyphae/media_hypha.go similarity index 53% rename from hyphae/hyphae.go rename to hyphae/media_hypha.go index 936ca33..8d3f532 100644 --- a/hyphae/hyphae.go +++ b/hyphae/media_hypha.go @@ -4,29 +4,11 @@ package hyphae import ( "log" "path/filepath" - "regexp" - "strings" "sync" "github.com/bouncepaw/mycorrhiza/files" ) -// HyphaPattern is a pattern which all hyphae names must match. -var HyphaPattern = regexp.MustCompile(`[^?!:#@><*|"'&%{}]+`) - -// IsValidName checks for invalid characters and path traversals. -func IsValidName(hyphaName string) bool { - if !HyphaPattern.MatchString(hyphaName) { - return false - } - for _, segment := range strings.Split(hyphaName, "/") { - if segment == ".git" || segment == ".." { - return false - } - } - return true -} - // MediaHypha keeps vital information about a media hypha type MediaHypha struct { sync.RWMutex @@ -77,59 +59,6 @@ func (h *MediaHypha) HasAttachment() bool { return h.binaryPath != "" } -var byNames = make(map[string]Hypher) -var byNamesMutex = sync.Mutex{} - -// EmptyHypha returns an empty hypha struct with given name. -func EmptyHypha(hyphaName string) *MediaHypha { - return &MediaHypha{ - name: hyphaName, - Exists: false, - TextPath: "", - binaryPath: "", - } -} - -// ByName returns a hypha by name. It may have been recorded to the storage. -func ByName(hyphaName string) (h Hypher) { - h, recorded := byNames[hyphaName] - if recorded { - return h - } - return EmptyHypha(hyphaName) -} - -func storeHypha(h Hypher) { - byNamesMutex.Lock() - byNames[h.CanonicalName()] = h - byNamesMutex.Unlock() - - h.Lock() - h.(*MediaHypha).Exists = true - h.Unlock() -} - -// insert inserts the hypha into the storage. A previous record is used if possible. Count incrementation is done if needed. -func insert(h Hypher) (madeNewRecord bool) { - hp, recorded := byNames[h.CanonicalName()] - if recorded { - hp.(*MediaHypha).mergeIn(h) - } else { - storeHypha(h) - incrementCount() - } - - return !recorded -} - -// InsertIfNew checks whether hypha exists and returns `true` if it didn't and has been created. -func InsertIfNew(h Hypher) (madeNewRecord bool) { - if h.DoesExist() { - return false - } - return insert(h) -} - // mergeIn merges in content file paths from a different hypha object. Prints warnings sometimes. func (h *MediaHypha) mergeIn(oh Hypher) { if h == oh {