mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2024-10-30 11:46:16 +00:00
174 lines
3.8 KiB
Go
174 lines
3.8 KiB
Go
package hyphae
|
|
|
|
import (
|
|
"errors"
|
|
"log"
|
|
"regexp"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/bouncepaw/mycorrhiza/markup"
|
|
"github.com/bouncepaw/mycorrhiza/util"
|
|
)
|
|
|
|
func init() {
|
|
markup.HyphaExists = func(hyphaName string) bool {
|
|
return ByName(hyphaName).Exists
|
|
}
|
|
markup.HyphaAccess = func(hyphaName string) (rawText, binaryBlock string, err error) {
|
|
if h := ByName(hyphaName); h.Exists {
|
|
rawText, err = h.FetchTextPart()
|
|
if h.BinaryPath != "" {
|
|
binaryBlock = h.BinaryHtmlBlock()
|
|
}
|
|
} else {
|
|
err = errors.New("Hypha " + hyphaName + " does not exist")
|
|
}
|
|
return
|
|
}
|
|
markup.HyphaIterate = func(λ func(string)) {
|
|
for h := range YieldExistingHyphae() {
|
|
λ(h.Name)
|
|
}
|
|
}
|
|
markup.HyphaImageForOG = func(hyphaName string) string {
|
|
if h := ByName(hyphaName); h.Exists && h.BinaryPath != "" {
|
|
return util.URL + "/binary/" + hyphaName
|
|
}
|
|
return util.URL + "/favicon.ico"
|
|
}
|
|
}
|
|
|
|
// HyphaPattern is a pattern which all hyphae must match.
|
|
var HyphaPattern = regexp.MustCompile(`[^?!:#@><*|"\'&%{}]+`)
|
|
|
|
type Hypha struct {
|
|
sync.RWMutex
|
|
|
|
Name string
|
|
Exists bool
|
|
TextPath string
|
|
BinaryPath string
|
|
OutLinks []*Hypha // not used yet
|
|
BackLinks []*Hypha // not used yet
|
|
}
|
|
|
|
var byNames = make(map[string]*Hypha)
|
|
var byNamesMutex = sync.Mutex{}
|
|
|
|
// YieldExistingHyphae iterates over all hyphae and yields all existing ones.
|
|
func YieldExistingHyphae() chan *Hypha {
|
|
ch := make(chan *Hypha)
|
|
go func(ch chan *Hypha) {
|
|
for _, h := range byNames {
|
|
if h.Exists {
|
|
ch <- h
|
|
}
|
|
}
|
|
close(ch)
|
|
}(ch)
|
|
return ch
|
|
}
|
|
|
|
// Subhyphae returns slice of subhyphae.
|
|
func (h *Hypha) Subhyphae() []*Hypha {
|
|
hyphae := []*Hypha{}
|
|
for subh := range YieldExistingHyphae() {
|
|
if strings.HasPrefix(subh.Name, h.Name+"/") {
|
|
hyphae = append(hyphae, subh)
|
|
}
|
|
}
|
|
return hyphae
|
|
}
|
|
|
|
// AreFreeNames checks if all given `hyphaNames` are not taken.
|
|
func AreFreeNames(hyphaNames ...string) (firstFailure string, ok bool) {
|
|
for h := range YieldExistingHyphae() {
|
|
for _, hn := range hyphaNames {
|
|
if hn == h.Name {
|
|
return hn, false
|
|
}
|
|
}
|
|
}
|
|
return "", true
|
|
}
|
|
|
|
// EmptyHypha returns an empty hypha struct with given name.
|
|
func EmptyHypha(hyphaName string) *Hypha {
|
|
return &Hypha{
|
|
Name: hyphaName,
|
|
Exists: false,
|
|
TextPath: "",
|
|
BinaryPath: "",
|
|
OutLinks: make([]*Hypha, 0),
|
|
BackLinks: make([]*Hypha, 0),
|
|
}
|
|
}
|
|
|
|
// ByName returns a hypha by name. If h.Exists, the returned hypha pointer is known to be part of the hypha index (byNames map).
|
|
func ByName(hyphaName string) (h *Hypha) {
|
|
byNamesMutex.Lock()
|
|
defer byNamesMutex.Unlock()
|
|
|
|
h, exists := byNames[hyphaName]
|
|
if exists {
|
|
return h
|
|
}
|
|
return EmptyHypha(hyphaName)
|
|
}
|
|
|
|
// Insert inserts the hypha into the storage. It overwrites the previous record, if there was any, and returns false. If the was no previous record, return true.
|
|
func (h *Hypha) Insert() (justCreated bool) {
|
|
var hp *Hypha
|
|
hp = ByName(h.Name)
|
|
|
|
byNamesMutex.Lock()
|
|
defer byNamesMutex.Unlock()
|
|
if hp.Exists {
|
|
hp = h
|
|
} else {
|
|
byNames[hp.Name] = h
|
|
}
|
|
|
|
return !hp.Exists
|
|
}
|
|
|
|
func (h *Hypha) InsertIfNew() (justCreated bool) {
|
|
if h.Exists {
|
|
return h.Insert()
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (h *Hypha) delete() {
|
|
byNamesMutex.Lock()
|
|
h.Lock()
|
|
delete(byNames, h.Name)
|
|
DecrementCount()
|
|
byNamesMutex.Unlock()
|
|
h.Unlock()
|
|
}
|
|
|
|
func (h *Hypha) renameTo(newName string) {
|
|
byNamesMutex.Lock()
|
|
h.Lock()
|
|
delete(byNames, h.Name)
|
|
h.Name = newName
|
|
byNames[h.Name] = h
|
|
byNamesMutex.Unlock()
|
|
h.Unlock()
|
|
}
|
|
|
|
// MergeIn merges in content file paths from a different hypha object. Prints warnings sometimes.
|
|
func (h *Hypha) MergeIn(oh *Hypha) {
|
|
if h.TextPath == "" && oh.TextPath != "" {
|
|
h.TextPath = oh.TextPath
|
|
}
|
|
if oh.BinaryPath != "" {
|
|
if h.BinaryPath != "" {
|
|
log.Println("There is a file collision for binary part of a hypha:", h.BinaryPath, "and", oh.BinaryPath, "-- going on with the latter")
|
|
}
|
|
h.BinaryPath = oh.BinaryPath
|
|
}
|
|
}
|