2021-02-04 15:47:09 +00:00
package hyphae
import (
2021-02-17 18:41:35 +00:00
"errors"
"log"
"regexp"
"strings"
2021-02-04 15:47:09 +00:00
"sync"
2021-02-17 18:41:35 +00:00
"github.com/bouncepaw/mycorrhiza/markup"
"github.com/bouncepaw/mycorrhiza/util"
2021-02-04 15:47:09 +00:00
)
2021-02-17 18:41:35 +00:00
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 ( ` [^?!:#@><*|"\'&% { }]+ ` )
2021-02-04 15:47:09 +00:00
type Hypha struct {
sync . RWMutex
Name string
Exists bool
TextPath string
BinaryPath string
2021-02-17 18:41:35 +00:00
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 )
2021-02-04 15:47:09 +00:00
}
2021-02-17 18:41:35 +00:00
// 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.
2021-02-04 15:47:09 +00:00
func ( h * Hypha ) Insert ( ) ( justCreated bool ) {
var hp * Hypha
2021-02-17 18:41:35 +00:00
hp = ByName ( h . Name )
2021-02-04 15:47:09 +00:00
2021-02-17 18:41:35 +00:00
byNamesMutex . Lock ( )
defer byNamesMutex . Unlock ( )
if hp . Exists {
2021-02-04 15:47:09 +00:00
hp = h
2021-02-17 18:41:35 +00:00
} else {
byNames [ hp . Name ] = h
2021-02-04 15:47:09 +00:00
}
2021-02-17 18:41:35 +00:00
return ! hp . Exists
}
2021-02-04 15:47:09 +00:00
2021-02-17 18:41:35 +00:00
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 ( )
2021-02-04 15:47:09 +00:00
h . Lock ( )
2021-02-17 18:41:35 +00:00
delete ( byNames , h . Name )
h . Name = newName
byNames [ h . Name ] = h
byNamesMutex . Unlock ( )
2021-02-04 15:47:09 +00:00
h . Unlock ( )
}
2021-02-17 18:41:35 +00:00
// 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
}
}