1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2025-01-22 08:06:52 +00:00
mycorrhiza/hyphae/hyphae.go

150 lines
3.4 KiB
Go
Raw Normal View History

2021-05-11 10:14:00 +00:00
// Package hyphae is for the Hypha type, hypha storage and stuff like that. It shall not depend on mycorrhiza modules other than util.
package hyphae
import (
2021-02-17 18:41:35 +00:00
"log"
2021-07-30 14:16:58 +00:00
"path/filepath"
2021-02-17 18:41:35 +00:00
"regexp"
"strings"
"sync"
"github.com/bouncepaw/mycorrhiza/files"
)
// HyphaPattern is a pattern which all hyphae names must match.
2021-05-11 10:14:00 +00:00
var HyphaPattern = regexp.MustCompile(`[^?!:#@><*|"'&%{}]+`)
2021-02-17 18:41:35 +00:00
// 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
}
// Hypha keeps vital information about a hypha
type Hypha struct {
sync.RWMutex
2022-02-03 22:29:01 +00:00
name string // Canonical name
Exists bool
2021-03-14 13:16:30 +00:00
TextPath string // == "" => no text part
2022-02-03 22:04:01 +00:00
binaryPath string // == "" => no attachment
2021-02-17 18:41:35 +00:00
}
2022-02-03 22:29:01 +00:00
func (h *Hypha) SetName(s string) { h.name = s }
2022-02-03 22:04:01 +00:00
func (h *Hypha) BinaryPath() string { return h.binaryPath }
func (h *Hypha) SetBinaryPath(s string) { h.binaryPath = s }
2022-02-03 21:26:08 +00:00
func (h *Hypha) CanonicalName() string {
2022-02-03 22:29:01 +00:00
return h.name
2022-02-03 21:26:08 +00:00
}
func (h *Hypha) Kind() HyphaKind {
if !h.DoesExist() {
2022-02-03 21:26:08 +00:00
return HyphaEmpty
}
if h.HasAttachment() {
return HyphaMedia
}
return HyphaText
}
func (h *Hypha) DoesExist() bool { // TODO: rename
return h.Exists
}
2022-02-03 21:26:08 +00:00
func (h *Hypha) HasTextPart() bool {
return h.TextPath != ""
}
2021-07-30 14:16:58 +00:00
// TextPartPath returns rooted path to the file where the text part should be.
func (h *Hypha) TextPartPath() string {
if h.TextPath == "" {
2022-02-03 22:29:01 +00:00
return filepath.Join(files.HyphaeDir(), h.name+".myco")
2021-07-30 14:16:58 +00:00
}
return h.TextPath
}
// HasAttachment is true if the hypha has an attachment.
func (h *Hypha) HasAttachment() bool {
2022-02-03 22:04:01 +00:00
return h.binaryPath != ""
}
var byNames = make(map[string]Hypher)
2021-02-17 18:41:35 +00:00
var byNamesMutex = sync.Mutex{}
// EmptyHypha returns an empty hypha struct with given name.
func EmptyHypha(hyphaName string) *Hypha {
return &Hypha{
2022-02-03 22:29:01 +00:00
name: hyphaName,
2021-02-17 18:41:35 +00:00
Exists: false,
TextPath: "",
2022-02-03 22:04:01 +00:00
binaryPath: "",
2021-02-17 18:41:35 +00:00
}
}
2021-03-14 13:16:30 +00:00
// ByName returns a hypha by name. It may have been recorded to the storage.
func ByName(hyphaName string) (h Hypher) {
2021-03-14 13:16:30 +00:00
h, recorded := byNames[hyphaName]
if recorded {
2021-02-17 18:41:35 +00:00
return h
}
return EmptyHypha(hyphaName)
}
func storeHypha(h Hypher) {
2021-02-17 18:41:35 +00:00
byNamesMutex.Lock()
byNames[h.CanonicalName()] = h
2021-03-14 13:16:30 +00:00
byNamesMutex.Unlock()
2021-03-14 15:20:02 +00:00
h.Lock()
h.(*Hypha).Exists = true
2021-03-14 15:20:02 +00:00
h.Unlock()
2021-03-14 13:16:30 +00:00
}
2021-12-20 20:59:23 +00:00
// 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()]
2021-03-14 13:16:30 +00:00
if recorded {
hp.(*Hypha).mergeIn(h)
2021-02-17 18:41:35 +00:00
} else {
2021-03-14 13:16:30 +00:00
storeHypha(h)
2021-12-20 20:59:23 +00:00
incrementCount()
}
2021-03-14 13:16:30 +00:00
return !recorded
2021-02-17 18:41:35 +00:00
}
// InsertIfNew checks whether hypha exists and returns `true` if it didn't and has been created.
func InsertIfNew(h Hypher) (madeNewRecord bool) {
2022-02-03 22:29:01 +00:00
if h.DoesExist() {
return false
2021-02-17 18:41:35 +00:00
}
2022-02-03 22:39:21 +00:00
return insert(h)
2021-02-17 18:41:35 +00:00
}
2021-12-20 20:59:23 +00:00
// mergeIn merges in content file paths from a different hypha object. Prints warnings sometimes.
func (h *Hypha) mergeIn(oh Hypher) {
2021-03-14 13:16:30 +00:00
if h == oh {
return
}
h.Lock()
if h.TextPath == "" && oh.HasTextPart() {
h.TextPath = oh.TextPartPath()
2021-02-17 18:41:35 +00:00
}
if oh := oh.(*Hypha); oh.Kind() == HyphaMedia {
2022-02-03 22:04:01 +00:00
if h.binaryPath != "" {
log.Println("There is a file collision for attachment of a hypha:", h.binaryPath, "and", oh.binaryPath, "-- going on with the latter")
2021-02-17 18:41:35 +00:00
}
2022-02-03 22:04:01 +00:00
h.binaryPath = oh.binaryPath
2021-02-17 18:41:35 +00:00
}
2021-03-14 13:16:30 +00:00
h.Unlock()
2021-03-02 16:36:57 +00:00
}