mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2025-07-25 12:12:48 +00:00
Move mimetype stuff to a separate module
This commit is contained in:
parent
d25c953409
commit
ae1c5db3b3
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
mycorrhiza
|
mycorrhiza
|
||||||
|
hyphae/*.gog
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/bouncepaw/mycorrhiza/history"
|
"github.com/bouncepaw/mycorrhiza/history"
|
||||||
"github.com/bouncepaw/mycorrhiza/markup"
|
"github.com/bouncepaw/mycorrhiza/markup"
|
||||||
|
"github.com/bouncepaw/mycorrhiza/mimetype"
|
||||||
"github.com/bouncepaw/mycorrhiza/templates"
|
"github.com/bouncepaw/mycorrhiza/templates"
|
||||||
"github.com/bouncepaw/mycorrhiza/tree"
|
"github.com/bouncepaw/mycorrhiza/tree"
|
||||||
"github.com/bouncepaw/mycorrhiza/user"
|
"github.com/bouncepaw/mycorrhiza/user"
|
||||||
@ -71,7 +72,7 @@ func handlerBinary(w http.ResponseWriter, rq *http.Request) {
|
|||||||
hyphaName := HyphaNameFromRq(rq, "binary")
|
hyphaName := HyphaNameFromRq(rq, "binary")
|
||||||
if data, ok := HyphaStorage[hyphaName]; ok {
|
if data, ok := HyphaStorage[hyphaName]; ok {
|
||||||
log.Println("Serving", data.binaryPath)
|
log.Println("Serving", data.binaryPath)
|
||||||
w.Header().Set("Content-Type", ExtensionToMime(filepath.Ext(data.binaryPath)))
|
w.Header().Set("Content-Type", mimetype.FromExtension(filepath.Ext(data.binaryPath)))
|
||||||
http.ServeFile(w, rq, data.binaryPath)
|
http.ServeFile(w, rq, data.binaryPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
87
hypha.go
87
hypha.go
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/bouncepaw/mycorrhiza/history"
|
"github.com/bouncepaw/mycorrhiza/history"
|
||||||
"github.com/bouncepaw/mycorrhiza/hyphae"
|
"github.com/bouncepaw/mycorrhiza/hyphae"
|
||||||
"github.com/bouncepaw/mycorrhiza/markup"
|
"github.com/bouncepaw/mycorrhiza/markup"
|
||||||
|
"github.com/bouncepaw/mycorrhiza/mimetype"
|
||||||
"github.com/bouncepaw/mycorrhiza/user"
|
"github.com/bouncepaw/mycorrhiza/user"
|
||||||
"github.com/bouncepaw/mycorrhiza/util"
|
"github.com/bouncepaw/mycorrhiza/util"
|
||||||
)
|
)
|
||||||
@ -114,7 +115,7 @@ func UploadBinary(hyphaName, mime string, file multipart.File, u *user.User) *hi
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return hop.WithError(err).Apply()
|
return hop.WithError(err).Apply()
|
||||||
}
|
}
|
||||||
return uploadHelp(hop, hyphaName, MimeToExtension(mime), data, u)
|
return uploadHelp(hop, hyphaName, mimetype.ToExtension(mime), data, u)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteHypha deletes hypha and makes a history record about that.
|
// DeleteHypha deletes hypha and makes a history record about that.
|
||||||
@ -254,48 +255,6 @@ func binaryHtmlBlock(hyphaName string, hd *HyphaData) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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. Do not touch the .git and static folders for they have an admnistrative importance!
|
|
||||||
if node.IsDir() && isCanonicalName(node.Name()) && node.Name() != ".git" && node.Name() != "static" {
|
|
||||||
Index(filepath.Join(path, node.Name()))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
hyphaPartPath = filepath.Join(path, node.Name())
|
|
||||||
hyphaName, isText, skip = DataFromFilename(hyphaPartPath)
|
|
||||||
hyphaData *HyphaData
|
|
||||||
)
|
|
||||||
if !skip {
|
|
||||||
// Reuse the entry for existing hyphae, create a new one for those that do not exist yet.
|
|
||||||
if hd, ok := HyphaStorage[hyphaName]; ok {
|
|
||||||
hyphaData = hd
|
|
||||||
} else {
|
|
||||||
hyphaData = &HyphaData{}
|
|
||||||
HyphaStorage[hyphaName] = hyphaData
|
|
||||||
hyphae.IncrementCount()
|
|
||||||
}
|
|
||||||
if isText {
|
|
||||||
hyphaData.textPath = hyphaPartPath
|
|
||||||
} else {
|
|
||||||
// Notify the user about binary part collisions. It's a design decision to just use any of them, it's the user's fault that they have screwed up the folder structure, but the engine should at least let them know, right?
|
|
||||||
if hyphaData.binaryPath != "" {
|
|
||||||
log.Println("There is a file collision for binary part of a hypha:", hyphaData.binaryPath, "and", hyphaPartPath, "-- going on with the latter")
|
|
||||||
}
|
|
||||||
hyphaData.binaryPath = hyphaPartPath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FetchTextPart tries to read text file in the `d`. If there is no file, empty string is returned.
|
// FetchTextPart tries to read text file in the `d`. If there is no file, empty string is returned.
|
||||||
func FetchTextPart(d *HyphaData) (string, error) {
|
func FetchTextPart(d *HyphaData) (string, error) {
|
||||||
if d.textPath == "" {
|
if d.textPath == "" {
|
||||||
@ -327,3 +286,45 @@ func setHeaderLinks() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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. Do not touch the .git and static folders for they have an admnistrative importance!
|
||||||
|
if node.IsDir() && isCanonicalName(node.Name()) && node.Name() != ".git" && node.Name() != "static" {
|
||||||
|
Index(filepath.Join(path, node.Name()))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
hyphaPartPath = filepath.Join(path, node.Name())
|
||||||
|
hyphaName, isText, skip = mimetype.DataFromFilename(hyphaPartPath)
|
||||||
|
hyphaData *HyphaData
|
||||||
|
)
|
||||||
|
if !skip {
|
||||||
|
// Reuse the entry for existing hyphae, create a new one for those that do not exist yet.
|
||||||
|
if hd, ok := HyphaStorage[hyphaName]; ok {
|
||||||
|
hyphaData = hd
|
||||||
|
} else {
|
||||||
|
hyphaData = &HyphaData{}
|
||||||
|
HyphaStorage[hyphaName] = hyphaData
|
||||||
|
hyphae.IncrementCount()
|
||||||
|
}
|
||||||
|
if isText {
|
||||||
|
hyphaData.textPath = hyphaPartPath
|
||||||
|
} else {
|
||||||
|
// Notify the user about binary part collisions. It's a design decision to just use any of them, it's the user's fault that they have screwed up the folder structure, but the engine should at least let them know, right?
|
||||||
|
if hyphaData.binaryPath != "" {
|
||||||
|
log.Println("There is a file collision for binary part of a hypha:", hyphaData.binaryPath, "and", hyphaPartPath, "-- going on with the latter")
|
||||||
|
}
|
||||||
|
hyphaData.binaryPath = hyphaPartPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
package hyphae
|
|
||||||
|
|
||||||
// TODO: do
|
|
||||||
import ()
|
|
||||||
|
|
||||||
type Hypha struct {
|
|
||||||
Name string
|
|
||||||
Exists bool
|
|
||||||
TextPath string
|
|
||||||
BinaryPath string
|
|
||||||
OutLinks []string
|
|
||||||
BackLinks []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddHypha adds a hypha named `name` with such `textPath` and `binaryPath`. Both paths can be empty. Does //not// check for hypha's existence beforehand. Count is handled.
|
|
||||||
func AddHypha(name, textPath, binaryPath string) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteHypha clears both paths and all out-links from the named hypha and marks it as non-existent. It does not actually delete it from the memdb. Count is handled.
|
|
||||||
func DeleteHypha(name string) {
|
|
||||||
}
|
|
3
main.go
3
main.go
@ -15,6 +15,7 @@ import (
|
|||||||
|
|
||||||
"github.com/bouncepaw/mycorrhiza/history"
|
"github.com/bouncepaw/mycorrhiza/history"
|
||||||
"github.com/bouncepaw/mycorrhiza/hyphae"
|
"github.com/bouncepaw/mycorrhiza/hyphae"
|
||||||
|
"github.com/bouncepaw/mycorrhiza/mimetype"
|
||||||
"github.com/bouncepaw/mycorrhiza/templates"
|
"github.com/bouncepaw/mycorrhiza/templates"
|
||||||
"github.com/bouncepaw/mycorrhiza/user"
|
"github.com/bouncepaw/mycorrhiza/user"
|
||||||
"github.com/bouncepaw/mycorrhiza/util"
|
"github.com/bouncepaw/mycorrhiza/util"
|
||||||
@ -64,7 +65,7 @@ func handlerList(w http.ResponseWriter, rq *http.Request) {
|
|||||||
u = user.FromRequest(rq)
|
u = user.FromRequest(rq)
|
||||||
)
|
)
|
||||||
for hyphaName, data := range HyphaStorage {
|
for hyphaName, data := range HyphaStorage {
|
||||||
tbody += templates.HyphaListRowHTML(hyphaName, ExtensionToMime(filepath.Ext(data.binaryPath)), data.binaryPath != "")
|
tbody += templates.HyphaListRowHTML(hyphaName, mimetype.FromExtension(filepath.Ext(data.binaryPath)), data.binaryPath != "")
|
||||||
}
|
}
|
||||||
util.HTTP200Page(w, base("List of pages", templates.HyphaListHTML(tbody, pageCount), u))
|
util.HTTP200Page(w, base("List of pages", templates.HyphaListHTML(tbody, pageCount), u))
|
||||||
}
|
}
|
||||||
|
62
mime.go
62
mime.go
@ -1,62 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MimeToExtension(mime string) string {
|
|
||||||
mm := map[string]string{
|
|
||||||
"application/octet-stream": "bin",
|
|
||||||
"image/jpeg": "jpg",
|
|
||||||
"image/gif": "gif",
|
|
||||||
"image/png": "png",
|
|
||||||
"image/webp": "webp",
|
|
||||||
"image/svg+xml": "svg",
|
|
||||||
"image/x-icon": "ico",
|
|
||||||
"application/ogg": "ogg",
|
|
||||||
"video/webm": "webm",
|
|
||||||
"audio/mp3": "mp3",
|
|
||||||
"video/mp4": "mp4",
|
|
||||||
}
|
|
||||||
if ext, ok := mm[mime]; ok {
|
|
||||||
return "." + ext
|
|
||||||
}
|
|
||||||
return ".bin"
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExtensionToMime(ext string) string {
|
|
||||||
mm := map[string]string{
|
|
||||||
".bin": "application/octet-stream",
|
|
||||||
".jpg": "image/jpeg",
|
|
||||||
".jpeg": "image/jpeg",
|
|
||||||
".gif": "image/gif",
|
|
||||||
".png": "image/png",
|
|
||||||
".webp": "image/webp",
|
|
||||||
".svg": "image/svg+xml",
|
|
||||||
".ico": "image/x-icon",
|
|
||||||
".ogg": "application/ogg",
|
|
||||||
".webm": "video/webm",
|
|
||||||
".mp3": "audio/mp3",
|
|
||||||
".mp4": "video/mp4",
|
|
||||||
}
|
|
||||||
if mime, ok := mm[ext]; ok {
|
|
||||||
return mime
|
|
||||||
}
|
|
||||||
return "application/octet-stream"
|
|
||||||
}
|
|
||||||
|
|
||||||
// DataFromFilename fetches all meta information from hypha content file with path `fullPath`. If it is not a content file, `skip` is true, and you are expected to ignore this file when indexing hyphae. `name` is name of the hypha to which this file relates. `isText` is true when the content file is text, false when is binary. `mimeId` is an integer representation of content type. Cast it to TextType if `isText == true`, cast it to BinaryType if `isText == false`.
|
|
||||||
func DataFromFilename(fullPath string) (name string, isText bool, skip bool) {
|
|
||||||
shortPath := strings.TrimPrefix(fullPath, WikiDir)[1:]
|
|
||||||
ext := filepath.Ext(shortPath)
|
|
||||||
name = CanonicalName(strings.TrimSuffix(shortPath, ext))
|
|
||||||
switch ext {
|
|
||||||
case ".myco":
|
|
||||||
isText = true
|
|
||||||
case "", shortPath:
|
|
||||||
skip = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
68
mimetype/mime.go
Normal file
68
mimetype/mime.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package mimetype
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/bouncepaw/mycorrhiza/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ToExtension returns dotted extension for given mime-type.
|
||||||
|
func ToExtension(mime string) string {
|
||||||
|
if ext, ok := mapMime2Ext[mime]; ok {
|
||||||
|
return "." + ext
|
||||||
|
}
|
||||||
|
return ".bin"
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromExtension returns mime-type for given extension. The extension must start with a dot.
|
||||||
|
func FromExtension(ext string) string {
|
||||||
|
if mime, ok := mapExt2Mime[ext]; ok {
|
||||||
|
return mime
|
||||||
|
}
|
||||||
|
return "application/octet-stream"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataFromFilename fetches all meta information from hypha content file with path `fullPath`. If it is not a content file, `skip` is true, and you are expected to ignore this file when indexing hyphae. `name` is name of the hypha to which this file relates. `isText` is true when the content file is text, false when is binary.
|
||||||
|
func DataFromFilename(fullPath string) (name string, isText bool, skip bool) {
|
||||||
|
shortPath := util.ShorterPath(fullPath)
|
||||||
|
ext := filepath.Ext(shortPath)
|
||||||
|
name = util.CanonicalName(strings.TrimSuffix(shortPath, ext))
|
||||||
|
switch ext {
|
||||||
|
case ".myco":
|
||||||
|
isText = true
|
||||||
|
case "", shortPath:
|
||||||
|
skip = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var mapMime2Ext = map[string]string{
|
||||||
|
"application/octet-stream": "bin",
|
||||||
|
"image/jpeg": "jpg",
|
||||||
|
"image/gif": "gif",
|
||||||
|
"image/png": "png",
|
||||||
|
"image/webp": "webp",
|
||||||
|
"image/svg+xml": "svg",
|
||||||
|
"image/x-icon": "ico",
|
||||||
|
"application/ogg": "ogg",
|
||||||
|
"video/webm": "webm",
|
||||||
|
"audio/mp3": "mp3",
|
||||||
|
"video/mp4": "mp4",
|
||||||
|
}
|
||||||
|
|
||||||
|
var mapExt2Mime = map[string]string{
|
||||||
|
".bin": "application/octet-stream",
|
||||||
|
".jpg": "image/jpeg",
|
||||||
|
".jpeg": "image/jpeg",
|
||||||
|
".gif": "image/gif",
|
||||||
|
".png": "image/png",
|
||||||
|
".webp": "image/webp",
|
||||||
|
".svg": "image/svg+xml",
|
||||||
|
".ico": "image/x-icon",
|
||||||
|
".ogg": "application/ogg",
|
||||||
|
".webm": "video/webm",
|
||||||
|
".mp3": "audio/mp3",
|
||||||
|
".mp4": "video/mp4",
|
||||||
|
}
|
14
util/util.go
14
util/util.go
@ -4,6 +4,7 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -65,3 +66,16 @@ func BeautifulName(uglyName string) string {
|
|||||||
}
|
}
|
||||||
return strings.Title(strings.ReplaceAll(uglyName, "_", " "))
|
return strings.Title(strings.ReplaceAll(uglyName, "_", " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CanonicalName makes sure the `name` is canonical. A name is canonical if it is lowercase and all spaces are replaced with underscores.
|
||||||
|
func CanonicalName(name string) string {
|
||||||
|
return strings.ToLower(strings.ReplaceAll(name, " ", "_"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// HyphaPattern is a pattern which all hyphae must match.
|
||||||
|
var HyphaPattern = regexp.MustCompile(`[^?!:#@><*|"\'&%{}]+`)
|
||||||
|
|
||||||
|
// IsCanonicalName checks if the `name` is canonical.
|
||||||
|
func IsCanonicalName(name string) bool {
|
||||||
|
return HyphaPattern.MatchString(name)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user