1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2025-01-07 02:10:26 +00:00

Use the Hypher interface in a lot of places

This commit is contained in:
Timur Ismagilov 2022-02-04 02:47:36 +05:00 committed by Timur Ismagilov
parent ff10d577d2
commit 927ac4f1da
15 changed files with 82 additions and 75 deletions

View File

@ -42,12 +42,12 @@ var backlinkIndex = make(map[string]linkSet)
func IndexBacklinks() { func IndexBacklinks() {
// It is safe to ignore the mutex, because there is only one worker. // It is safe to ignore the mutex, because there is only one worker.
for h := range hyphae.FilterHyphaeWithText(hyphae.YieldExistingHyphae()) { for h := range hyphae.FilterHyphaeWithText(hyphae.YieldExistingHyphae()) {
foundLinks := extractHyphaLinksFromContent(h.Name, fetchText(h)) foundLinks := extractHyphaLinksFromContent(h.CanonicalName(), fetchText(h))
for _, link := range foundLinks { for _, link := range foundLinks {
if _, exists := backlinkIndex[link]; !exists { if _, exists := backlinkIndex[link]; !exists {
backlinkIndex[link] = make(linkSet) backlinkIndex[link] = make(linkSet)
} }
backlinkIndex[link][h.Name] = struct{}{} backlinkIndex[link][h.CanonicalName()] = struct{}{}
} }
} }
} }
@ -71,11 +71,11 @@ func toLinkSet(xs []string) linkSet {
return result return result
} }
func fetchText(h *hyphae.Hypha) string { func fetchText(h hyphae.Hypher) string {
if h.TextPath == "" { if !h.HasTextPart() {
return "" return ""
} }
text, err := os.ReadFile(h.TextPath) text, err := os.ReadFile(h.TextPartPath())
if err == nil { if err == nil {
return string(text) return string(text)
} }

View File

@ -51,6 +51,10 @@ func (h *Hypha) Kind() HyphaKind {
return HyphaText return HyphaText
} }
func (h *Hypha) DoesExist() bool { // TODO: rename
return h.Exists
}
func (h *Hypha) HasTextPart() bool { func (h *Hypha) HasTextPart() bool {
return h.TextPath != "" return h.TextPath != ""
} }

View File

@ -16,6 +16,7 @@ type Hypher interface {
CanonicalName() string CanonicalName() string
Kind() HyphaKind Kind() HyphaKind
DoesExist() bool
HasTextPart() bool HasTextPart() bool
TextPartPath() string TextPartPath() string

View File

@ -7,20 +7,20 @@ import (
// Iteration represents an iteration over all hyphae in the storage. You may use it instead of directly iterating using hyphae.YieldExistingHyphae when you want to do n checks at once instead of iterating n times. // Iteration represents an iteration over all hyphae in the storage. You may use it instead of directly iterating using hyphae.YieldExistingHyphae when you want to do n checks at once instead of iterating n times.
type Iteration struct { type Iteration struct {
sync.Mutex sync.Mutex
iterator func() chan *Hypha iterator func() chan Hypher
checks []func(h *Hypha) CheckResult checks []func(h Hypher) CheckResult
} }
// NewIteration constructs an iteration without checks. // NewIteration constructs an iteration without checks.
func NewIteration() *Iteration { func NewIteration() *Iteration {
return &Iteration{ return &Iteration{
iterator: YieldExistingHyphae, iterator: YieldExistingHyphae,
checks: make([]func(h *Hypha) CheckResult, 0), checks: make([]func(h Hypher) CheckResult, 0),
} }
} }
// AddCheck adds the check to the iteration. It is concurrent-safe. // AddCheck adds the check to the iteration. It is concurrent-safe.
func (i7n *Iteration) AddCheck(check func(h *Hypha) CheckResult) { func (i7n *Iteration) AddCheck(check func(h Hypher) CheckResult) {
i7n.Lock() i7n.Lock()
i7n.checks = append(i7n.checks, check) i7n.checks = append(i7n.checks, check)
i7n.Unlock() i7n.Unlock()

View File

@ -8,8 +8,8 @@ import (
) )
// YieldExistingHyphae iterates over all hyphae and yields all existing ones. // YieldExistingHyphae iterates over all hyphae and yields all existing ones.
func YieldExistingHyphae() chan *Hypha { func YieldExistingHyphae() chan Hypher {
ch := make(chan *Hypha) ch := make(chan Hypher)
go func() { go func() {
for _, h := range byNames { for _, h := range byNames {
if h.Exists { if h.Exists {
@ -22,12 +22,12 @@ func YieldExistingHyphae() chan *Hypha {
} }
// FilterHyphaeWithText filters the source channel and yields only those hyphae than have text parts. // FilterHyphaeWithText filters the source channel and yields only those hyphae than have text parts.
func FilterHyphaeWithText(src chan *Hypha) chan *Hypha { func FilterHyphaeWithText(src chan Hypher) chan Hypher {
// TODO: reimplement as a function with a callback? // TODO: reimplement as a function with a callback?
sink := make(chan *Hypha) sink := make(chan Hypher)
go func() { go func() {
for h := range src { for h := range src {
if h.TextPath != "" { if h.HasTextPart() {
sink <- h sink <- h
} }
} }
@ -79,10 +79,10 @@ func PathographicSort(src chan string) <-chan string {
} }
// Subhyphae returns slice of subhyphae. // Subhyphae returns slice of subhyphae.
func (h *Hypha) Subhyphae() []*Hypha { func Subhyphae(h Hypher) []Hypher {
var hyphae []*Hypha var hyphae []Hypher
for subh := range YieldExistingHyphae() { for subh := range YieldExistingHyphae() {
if strings.HasPrefix(subh.Name, h.Name+"/") { if strings.HasPrefix(subh.CanonicalName(), h.CanonicalName()+"/") {
hyphae = append(hyphae, subh) hyphae = append(hyphae, subh)
} }
} }
@ -93,7 +93,7 @@ func (h *Hypha) Subhyphae() []*Hypha {
func AreFreeNames(hyphaNames ...string) (firstFailure string, ok bool) { func AreFreeNames(hyphaNames ...string) (firstFailure string, ok bool) {
for h := range YieldExistingHyphae() { for h := range YieldExistingHyphae() {
for _, hn := range hyphaNames { for _, hn := range hyphaNames {
if hn == h.Name { if hn == h.CanonicalName() {
return hn, false return hn, false
} }
} }

View File

@ -9,20 +9,20 @@ import (
) )
func canFactory( func canFactory(
rejectLogger func(*hyphae.Hypha, *user.User, string), rejectLogger func(hyphae.Hypher, *user.User, string),
action string, action string,
dispatcher func(*hyphae.Hypha, *user.User, *l18n.Localizer) (string, string), dispatcher func(hyphae.Hypher, *user.User, *l18n.Localizer) (string, string),
noRightsMsg string, noRightsMsg string,
notExistsMsg string, notExistsMsg string,
mustExist bool, mustExist bool,
) func(*user.User, *hyphae.Hypha, *l18n.Localizer) (string, error) { ) func(*user.User, hyphae.Hypher, *l18n.Localizer) (string, error) {
return func(u *user.User, h *hyphae.Hypha, lc *l18n.Localizer) (string, error) { return func(u *user.User, h hyphae.Hypher, lc *l18n.Localizer) (string, error) {
if !u.CanProceed(action) { if !u.CanProceed(action) {
rejectLogger(h, u, "no rights") rejectLogger(h, u, "no rights")
return lc.Get("ui.act_no_rights"), errors.New(lc.Get(noRightsMsg)) return lc.Get("ui.act_no_rights"), errors.New(lc.Get(noRightsMsg))
} }
if mustExist && !h.Exists { if mustExist && !h.DoesExist() {
rejectLogger(h, u, "does not exist") rejectLogger(h, u, "does not exist")
return lc.Get("ui.act_notexist"), errors.New(lc.Get(notExistsMsg)) return lc.Get("ui.act_notexist"), errors.New(lc.Get(notExistsMsg))
} }
@ -61,8 +61,8 @@ var (
CanUnattach = canFactory( CanUnattach = canFactory(
rejectUnattachLog, rejectUnattachLog,
"unattach-confirm", "unattach-confirm",
func(h *hyphae.Hypha, u *user.User, lc *l18n.Localizer) (errmsg, errtitle string) { func(h hyphae.Hypher, u *user.User, lc *l18n.Localizer) (errmsg, errtitle string) {
if h.BinaryPath == "" { if h.Kind() != hyphae.HyphaMedia {
rejectUnattachLog(h, u, "no amnt") rejectUnattachLog(h, u, "no amnt")
return lc.Get("ui.act_noattachment_tip"), lc.Get("ui.act_noattachment") return lc.Get("ui.act_noattachment_tip"), lc.Get("ui.act_noattachment")
} }

View File

@ -27,7 +27,7 @@ func init() {
} }
globals.HyphaIterate = func(λ func(string)) { globals.HyphaIterate = func(λ func(string)) {
for h := range hyphae.YieldExistingHyphae() { for h := range hyphae.YieldExistingHyphae() {
λ(h.Name) λ(h.CanonicalName())
} }
} }
} }

View File

@ -7,18 +7,18 @@ import (
"github.com/bouncepaw/mycorrhiza/user" "github.com/bouncepaw/mycorrhiza/user"
) )
func rejectDeleteLog(h *hyphae.Hypha, u *user.User, errmsg string) { func rejectDeleteLog(h hyphae.Hypher, u *user.User, errmsg string) {
log.Printf("Reject delete %s by @%s: %s\n", h.Name, u.Name, errmsg) log.Printf("Reject delete %s by @%s: %s\n", h.CanonicalName(), u.Name, errmsg)
} }
func rejectRenameLog(h *hyphae.Hypha, u *user.User, errmsg string) { func rejectRenameLog(h hyphae.Hypher, u *user.User, errmsg string) {
log.Printf("Reject rename %s by @%s: %s\n", h.Name, u.Name, errmsg) log.Printf("Reject rename %s by @%s: %s\n", h.CanonicalName(), u.Name, errmsg)
} }
func rejectUnattachLog(h *hyphae.Hypha, u *user.User, errmsg string) { func rejectUnattachLog(h hyphae.Hypher, u *user.User, errmsg string) {
log.Printf("Reject unattach %s by @%s: %s\n", h.Name, u.Name, errmsg) log.Printf("Reject unattach %s by @%s: %s\n", h.CanonicalName(), u.Name, errmsg)
} }
func rejectEditLog(h *hyphae.Hypha, u *user.User, errmsg string) { func rejectEditLog(h hyphae.Hypher, u *user.User, errmsg string) {
log.Printf("Reject edit %s by @%s: %s\n", h.Name, u.Name, errmsg) log.Printf("Reject edit %s by @%s: %s\n", h.CanonicalName(), u.Name, errmsg)
} }
func rejectAttachLog(h *hyphae.Hypha, u *user.User, errmsg string) { func rejectAttachLog(h hyphae.Hypher, u *user.User, errmsg string) {
log.Printf("Reject attach %s by @%s: %s\n", h.Name, u.Name, errmsg) log.Printf("Reject attach %s by @%s: %s\n", h.CanonicalName(), u.Name, errmsg)
} }

View File

@ -13,19 +13,19 @@ import (
"github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/util"
) )
func canRenameThisToThat(oh *hyphae.Hypha, nh *hyphae.Hypha, u *user.User, lc *l18n.Localizer) (errtitle string, err error) { func canRenameThisToThat(oh hyphae.Hypher, nh hyphae.Hypher, u *user.User, lc *l18n.Localizer) (errtitle string, err error) {
if nh.Exists { if nh.DoesExist() {
rejectRenameLog(oh, u, fmt.Sprintf("name %s taken already", nh.Name)) rejectRenameLog(oh, u, fmt.Sprintf("name %s taken already", nh.CanonicalName()))
return lc.Get("ui.rename_taken"), fmt.Errorf(lc.Get("ui.rename_taken_tip", &l18n.Replacements{"name": "<a href='/hypha/%[1]s'>%[1]s</a>"}), nh.Name) return lc.Get("ui.rename_taken"), fmt.Errorf(lc.Get("ui.rename_taken_tip", &l18n.Replacements{"name": "<a href='/hypha/%[1]s'>%[1]s</a>"}), nh.CanonicalName())
} }
if nh.Name == "" { if nh.CanonicalName() == "" {
rejectRenameLog(oh, u, "no new name given") rejectRenameLog(oh, u, "no new name given")
return lc.Get("ui.rename_noname"), errors.New(lc.Get("ui.rename_noname_tip")) return lc.Get("ui.rename_noname"), errors.New(lc.Get("ui.rename_noname_tip"))
} }
if !hyphae.IsValidName(nh.Name) { if !hyphae.IsValidName(nh.CanonicalName()) {
rejectRenameLog(oh, u, fmt.Sprintf("new name %s invalid", nh.Name)) rejectRenameLog(oh, u, fmt.Sprintf("new name %s invalid", nh.CanonicalName()))
return lc.Get("ui.rename_badname"), errors.New(lc.Get("ui.rename_badname_tip", &l18n.Replacements{"chars": "<code>^?!:#@&gt;&lt;*|\"\\'&amp;%</code>"})) return lc.Get("ui.rename_badname"), errors.New(lc.Get("ui.rename_badname_tip", &l18n.Replacements{"chars": "<code>^?!:#@&gt;&lt;*|\"\\'&amp;%</code>"}))
} }
@ -33,7 +33,7 @@ func canRenameThisToThat(oh *hyphae.Hypha, nh *hyphae.Hypha, u *user.User, lc *l
} }
// RenameHypha renames hypha from old name `hyphaName` to `newName` and makes a history record about that. If `recursive` is `true`, its subhyphae will be renamed the same way. // RenameHypha renames hypha from old name `hyphaName` to `newName` and makes a history record about that. If `recursive` is `true`, its subhyphae will be renamed the same way.
func RenameHypha(h *hyphae.Hypha, newHypha *hyphae.Hypha, recursive bool, u *user.User, lc *l18n.Localizer) (hop *history.Op, errtitle string) { func RenameHypha(h hyphae.Hypher, newHypha hyphae.Hypher, recursive bool, u *user.User, lc *l18n.Localizer) (hop *history.Op, errtitle string) {
newHypha.Lock() newHypha.Lock()
defer newHypha.Unlock() defer newHypha.Unlock()
hop = history.Operation(history.TypeRenameHypha) hop = history.Operation(history.TypeRenameHypha)
@ -48,9 +48,9 @@ func RenameHypha(h *hyphae.Hypha, newHypha *hyphae.Hypha, recursive bool, u *use
} }
var ( var (
re = regexp.MustCompile(`(?i)` + h.Name) re = regexp.MustCompile(`(?i)` + h.CanonicalName())
replaceName = func(str string) string { replaceName = func(str string) string {
return re.ReplaceAllString(util.CanonicalName(str), newHypha.Name) return re.ReplaceAllString(util.CanonicalName(str), newHypha.CanonicalName())
} }
hyphaeToRename = findHyphaeToRename(h, recursive) hyphaeToRename = findHyphaeToRename(h, recursive)
renameMap, err = renamingPairs(hyphaeToRename, replaceName) renameMap, err = renamingPairs(hyphaeToRename, replaceName)
@ -64,13 +64,14 @@ func RenameHypha(h *hyphae.Hypha, newHypha *hyphae.Hypha, recursive bool, u *use
renameMsg += " recursively" renameMsg += " recursively"
} }
hop.WithFilesRenamed(renameMap). hop.WithFilesRenamed(renameMap).
WithMsg(fmt.Sprintf(renameMsg, h.Name, newHypha.Name)). WithMsg(fmt.Sprintf(renameMsg, h.CanonicalName(), newHypha.CanonicalName())).
WithUser(u). WithUser(u).
Apply() Apply()
if len(hop.Errs) == 0 { if len(hop.Errs) == 0 {
for _, h := range hyphaeToRename { for _, h := range hyphaeToRename {
oldName := h.Name h := h.(*hyphae.Hypha) // ontology think
h.RenameTo(replaceName(h.Name)) oldName := h.CanonicalName()
h.RenameTo(replaceName(h.CanonicalName()))
h.Lock() h.Lock()
h.TextPath = replaceName(h.TextPath) h.TextPath = replaceName(h.TextPath)
h.BinaryPath = replaceName(h.BinaryPath) h.BinaryPath = replaceName(h.BinaryPath)
@ -81,24 +82,25 @@ func RenameHypha(h *hyphae.Hypha, newHypha *hyphae.Hypha, recursive bool, u *use
return hop, "" return hop, ""
} }
func findHyphaeToRename(superhypha *hyphae.Hypha, recursive bool) []*hyphae.Hypha { func findHyphaeToRename(superhypha hyphae.Hypher, recursive bool) []hyphae.Hypher {
hyphae := []*hyphae.Hypha{superhypha} hyphaList := []hyphae.Hypher{superhypha}
if recursive { if recursive {
hyphae = append(hyphae, superhypha.Subhyphae()...) hyphaList = append(hyphaList, hyphae.Subhyphae(superhypha)...)
} }
return hyphae return hyphaList
} }
func renamingPairs(hyphaeToRename []*hyphae.Hypha, replaceName func(string) string) (map[string]string, error) { func renamingPairs(hyphaeToRename []hyphae.Hypher, replaceName func(string) string) (map[string]string, error) {
renameMap := make(map[string]string) renameMap := make(map[string]string)
newNames := make([]string, len(hyphaeToRename)) newNames := make([]string, len(hyphaeToRename))
for _, h := range hyphaeToRename { for _, h := range hyphaeToRename {
h.Lock() h.Lock()
newNames = append(newNames, replaceName(h.Name)) newNames = append(newNames, replaceName(h.CanonicalName()))
if h.TextPath != "" { if h.HasTextPart() {
renameMap[h.TextPath] = replaceName(h.TextPath) renameMap[h.TextPartPath()] = replaceName(h.TextPartPath())
} }
if h.BinaryPath != "" { if h.Kind() == hyphae.HyphaMedia { // ontology think
h := h.(*hyphae.Hypha)
renameMap[h.BinaryPath] = replaceName(h.BinaryPath) renameMap[h.BinaryPath] = replaceName(h.BinaryPath)
} }
h.Unlock() h.Unlock()

View File

@ -14,8 +14,8 @@ func YieldHyphaNamesContainingString(query string) <-chan string {
sorted := hyphae.PathographicSort(out) sorted := hyphae.PathographicSort(out)
go func() { go func() {
for h := range hyphae.YieldExistingHyphae() { for h := range hyphae.YieldExistingHyphae() {
if hyphaNameMatchesString(h.Name, query) { if hyphaNameMatchesString(h.CanonicalName(), query) {
out <- h.Name out <- h.CanonicalName()
} }
} }
close(out) close(out)

View File

@ -18,25 +18,25 @@ func findSiblings(hyphaName string) []*sibling {
} }
var ( var (
siblingsMap = make(map[string]bool) siblingsMap = make(map[string]bool)
siblingCheck = func(h *hyphae.Hypha) hyphae.CheckResult { siblingCheck = func(h hyphae.Hypher) hyphae.CheckResult {
switch { switch {
case h.Name == hyphaName, // Hypha is no sibling of itself case h.CanonicalName() == hyphaName, // Hypha is no sibling of itself
h.Name == parentHyphaName: // Parent hypha is no sibling of its child h.CanonicalName() == parentHyphaName: // Parent hypha is no sibling of its child
return hyphae.CheckContinue return hyphae.CheckContinue
} }
if (parentHyphaName != "" && strings.HasPrefix(h.Name, parentHyphaName+"/")) || if (parentHyphaName != "" && strings.HasPrefix(h.CanonicalName(), parentHyphaName+"/")) ||
(parentHyphaName == "") { (parentHyphaName == "") {
var ( var (
rawSubPath = strings.TrimPrefix(h.Name, parentHyphaName)[1:] rawSubPath = strings.TrimPrefix(h.CanonicalName(), parentHyphaName)[1:]
slashIdx = strings.IndexRune(rawSubPath, '/') slashIdx = strings.IndexRune(rawSubPath, '/')
) )
if slashIdx > -1 { if slashIdx > -1 {
var sibPath = h.Name[:slashIdx+len(parentHyphaName)+1] var sibPath = h.CanonicalName()[:slashIdx+len(parentHyphaName)+1]
if _, exists := siblingsMap[sibPath]; !exists { if _, exists := siblingsMap[sibPath]; !exists {
siblingsMap[sibPath] = false siblingsMap[sibPath] = false
} }
} else { // it is a straight sibling } else { // it is a straight sibling
siblingsMap[h.Name] = true siblingsMap[h.CanonicalName()] = true
} }
} }
return hyphae.CheckContinue return hyphae.CheckContinue
@ -63,12 +63,12 @@ func findSiblings(hyphaName string) []*sibling {
func countSubhyphae(siblings []*sibling) { func countSubhyphae(siblings []*sibling) {
var ( var (
subhyphaCheck = func(h *hyphae.Hypha) hyphae.CheckResult { subhyphaCheck = func(h hyphae.Hypher) hyphae.CheckResult {
for _, s := range siblings { for _, s := range siblings {
if path.Dir(h.Name) == s.name { if path.Dir(h.CanonicalName()) == s.name {
s.directSubhyphaeCount++ s.directSubhyphaeCount++
return hyphae.CheckContinue return hyphae.CheckContinue
} else if strings.HasPrefix(h.Name, s.name+"/") { } else if strings.HasPrefix(h.CanonicalName(), s.name+"/") {
s.indirectSubhyphaeCount++ s.indirectSubhyphaeCount++
return hyphae.CheckContinue return hyphae.CheckContinue
} }
@ -136,7 +136,7 @@ func figureOutChildren(hyphaName string) child {
) )
for desc := range hyphae.YieldExistingHyphae() { for desc := range hyphae.YieldExistingHyphae() {
var descName = desc.Name var descName = desc.CanonicalName()
if strings.HasPrefix(descName, descPrefix) { if strings.HasPrefix(descName, descPrefix) {
var subPath = strings.TrimPrefix(descName, descPrefix) var subPath = strings.TrimPrefix(descName, descPrefix)
addHyphaToChild(descName, subPath, &child) addHyphaToChild(descName, subPath, &child)

View File

@ -257,7 +257,7 @@ sort.Strings(editors)
hyphaNames := make(chan string) hyphaNames := make(chan string)
sortedHypha := hyphae.PathographicSort(hyphaNames) sortedHypha := hyphae.PathographicSort(hyphaNames)
for hypha := range hyphae.YieldExistingHyphae() { for hypha := range hyphae.YieldExistingHyphae() {
hyphaNames <- hypha.Name hyphaNames <- hypha.CanonicalName()
} }
close(hyphaNames) close(hyphaNames)
%} %}

View File

@ -1007,7 +1007,7 @@ func StreamHyphaListHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) {
hyphaNames := make(chan string) hyphaNames := make(chan string)
sortedHypha := hyphae.PathographicSort(hyphaNames) sortedHypha := hyphae.PathographicSort(hyphaNames)
for hypha := range hyphae.YieldExistingHyphae() { for hypha := range hyphae.YieldExistingHyphae() {
hyphaNames <- hypha.Name hyphaNames <- hypha.CanonicalName()
} }
close(hyphaNames) close(hyphaNames)

View File

@ -35,7 +35,7 @@ func initMutators(r *mux.Router) {
func factoryHandlerAsker( func factoryHandlerAsker(
actionPath string, actionPath string,
asker func(*user.User, *hyphae.Hypha, *l18n.Localizer) (string, error), asker func(*user.User, hyphae.Hypher, *l18n.Localizer) (string, error),
succTitleKey string, succTitleKey string,
succPageTemplate func(*http.Request, string, bool) string, succPageTemplate func(*http.Request, string, bool) string,
) func(http.ResponseWriter, *http.Request) { ) func(http.ResponseWriter, *http.Request) {

View File

@ -145,7 +145,7 @@ func handlerRandom(w http.ResponseWriter, rq *http.Request) {
i := rand.Intn(amountOfHyphae) i := rand.Intn(amountOfHyphae)
for h := range hyphae.YieldExistingHyphae() { for h := range hyphae.YieldExistingHyphae() {
if i == 0 { if i == 0 {
randomHyphaName = h.Name randomHyphaName = h.CanonicalName()
} }
i-- i--
} }