1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-10-30 11:46:16 +00:00
mycorrhiza/hypha.go

163 lines
4.5 KiB
Go
Raw Normal View History

package main
import (
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
2020-10-02 15:31:59 +00:00
"strings"
"github.com/bouncepaw/mycorrhiza/gemtext"
2020-09-29 15:04:22 +00:00
"github.com/bouncepaw/mycorrhiza/history"
)
func init() {
gemtext.HyphaExists = func(hyphaName string) bool {
_, hyphaExists := HyphaStorage[hyphaName]
return hyphaExists
}
gemtext.HyphaAccess = func(hyphaName string) (rawText, binaryBlock string, err error) {
if hyphaData, ok := HyphaStorage[hyphaName]; ok {
rawText, err = FetchTextPart(hyphaData)
if hyphaData.binaryPath != "" {
binaryBlock = binaryHtmlBlock(hyphaName, hyphaData)
}
} else {
err = errors.New("Hypha " + hyphaName + " does not exist")
}
return
}
}
// HyphaData represents a hypha's meta information: binary and text parts rooted paths and content types.
type HyphaData struct {
textPath string
textType TextType
binaryPath string
binaryType BinaryType
}
2020-09-29 15:04:22 +00:00
// DeleteHypha deletes hypha and makes a history record about that.
func (hd *HyphaData) DeleteHypha(hyphaName string) *history.HistoryOp {
2020-10-03 14:19:49 +00:00
hop := history.Operation(history.TypeDeleteHypha).
2020-09-29 15:04:22 +00:00
WithFilesRemoved(hd.textPath, hd.binaryPath).
WithMsg(fmt.Sprintf("Delete %s", hyphaName)).
WithSignature("anon").
Apply()
2020-10-03 14:19:49 +00:00
if len(hop.Errs) == 0 {
delete(HyphaStorage, hyphaName)
}
return hop
2020-09-29 15:04:22 +00:00
}
2020-10-02 15:31:59 +00:00
// RenameHypha renames hypha from old name `hyphaName` to `newName` and makes a history record about that.
func (hd *HyphaData) RenameHypha(hyphaName, newName string) *history.HistoryOp {
var (
newTextPath = strings.Replace(hd.textPath, hyphaName, newName, 1)
newBinaryPath = strings.Replace(hd.binaryPath, hyphaName, newName, 1)
hop = history.Operation(history.TypeRenameHypha).
WithFilesRenamed(map[string]string{
hd.textPath: newTextPath,
hd.binaryPath: newBinaryPath,
}).
WithMsg(fmt.Sprintf("Rename %s to %s", hyphaName, newName)).
WithSignature("anon").
Apply()
)
if len(hop.Errs) == 0 {
hd.textPath = newTextPath
hd.binaryPath = newBinaryPath
HyphaStorage[newName] = hd
delete(HyphaStorage, hyphaName)
}
return hop
}
// binaryHtmlBlock creates an html block for binary part of the hypha.
func binaryHtmlBlock(hyphaName string, d *HyphaData) string {
switch d.binaryType {
case BinaryJpeg, BinaryGif, BinaryPng, BinaryWebp, BinarySvg, BinaryIco:
return fmt.Sprintf(`
<div class="binary-container binary-container_with-img">
<img src="/binary/%s"/>
</div>`, hyphaName)
case BinaryOgg, BinaryWebm, BinaryMp4:
return fmt.Sprintf(`
<div class="binary-container binary-container_with-video">
<video>
<source src="/binary/%[1]s"/>
<p>Your browser does not support video. See video's <a href="/binary/%[1]s">direct url</a></p>
</video>
`, hyphaName)
case BinaryMp3:
return fmt.Sprintf(`
<div class="binary-container binary-container_with-audio">
<audio>
<source src="/binary/%[1]s"/>
<p>Your browser does not support audio. See audio's <a href="/binary/%[1]s">direct url</a></p>
</audio>
`, hyphaName)
default:
return fmt.Sprintf(`
<div class="binary-container binary-container_with-nothing">
<p>This hypha's media cannot be rendered. Access it <a href="/binary/%s">directly</a></p>
</div>
`, hyphaName)
}
}
// Index finds all hypha files in the full `path` and saves them to HyphaStorage. This function is recursive.
func Index(path string) {
nodes, err := ioutil.ReadDir(path)
if err != nil {
log.Fatal(err)
}
for _, node := range nodes {
// If this hypha looks like it can be a hypha path, go deeper
if node.IsDir() && isCanonicalName(node.Name()) {
Index(filepath.Join(path, node.Name()))
}
hyphaPartFilename := filepath.Join(path, node.Name())
skip, hyphaName, isText, mimeId := DataFromFilename(hyphaPartFilename)
if !skip {
var (
hyphaData *HyphaData
ok bool
)
if hyphaData, ok = HyphaStorage[hyphaName]; !ok {
hyphaData = &HyphaData{}
HyphaStorage[hyphaName] = hyphaData
}
if isText {
hyphaData.textPath = hyphaPartFilename
hyphaData.textType = TextType(mimeId)
} else {
hyphaData.binaryPath = hyphaPartFilename
hyphaData.binaryType = BinaryType(mimeId)
}
}
}
}
// FetchTextPart tries to read text file in the `d`. If there is no file, empty string is returned.
func FetchTextPart(d *HyphaData) (string, error) {
if d.textPath == "" {
return "", nil
}
_, err := os.Stat(d.textPath)
if os.IsNotExist(err) {
return "", nil
} else if err != nil {
return "", err
}
text, err := ioutil.ReadFile(d.textPath)
if err != nil {
return "", err
}
return string(text), nil
}