miki

Miki: personal wiki with the fmd markup format
git clone https://wtenison.com/repo/miki.git
Log | Files | Refs | README | LICENSE

commit 26ff2bb7237b5abbc0978cf0b269ddbd20467f9d
parent 601ea12d68287e7674e71da71370037c73ab4e55
Author: weetat <wtenison@protonmail.com>
Date:   Mon, 24 Feb 2025 03:13:12 +0000

Split main into filesystem and network packages

Also move script.js and styles.css into web/global so other pages can
share them.

Diffstat:
Asrc/filesystem/filesystem.go | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/miki/miki.go | 201++-----------------------------------------------------------------------------
Asrc/network/network.go | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rweb/home/script.js -> web/global/script.js | 0
Rweb/home/styles.css -> web/global/styles.css | 0
Mweb/home/index.html | 4++--
6 files changed, 267 insertions(+), 198 deletions(-)

diff --git a/src/filesystem/filesystem.go b/src/filesystem/filesystem.go @@ -0,0 +1,139 @@ +package filesystem + +import ( + "bytes" + "fmt" + "log" + "os" + "path/filepath" + "regexp" + + "github.com/goccy/go-yaml" +) + +var FilePatternHTML = regexp.MustCompile("^([a-zA-Z0-9.]+).html$") + +var Paths struct { + RootDirectory string + WebDirectory string +} + +var GlobalPkg DirectoryPackage + +type DirectorySignature struct { + Root string // The root directoy of the resource. + DependencyDepth int // The folder search depth of the resource. -1=inf, 0=single, >0=n-depth + DependencyPattern *regexp.Regexp // The pattern of valid resource dependency files. +} + +type DirectoryPackage struct { + Root string // The root directory of the resource. + DependencyFiles []string // The set of valid resource files. + DependencyData IDirectoryData // Any relevant resource data. +} + +type IDirectoryData interface { +} + +func MakeDirectorySig(directory string, depth int, pattern *regexp.Regexp) (DirectorySignature, error) { + + if directory == "" || depth < -1 || pattern == nil { + return DirectorySignature{}, fmt.Errorf("invalid directory signature (%s, %d, %s)", directory, depth, pattern) + } + + if _, _err := os.Stat(directory); _err != nil { + return DirectorySignature{}, _err + } + + return DirectorySignature{directory, depth, pattern}, nil +} + +func MakeDirectoryPkg(resSig DirectorySignature) (DirectoryPackage, error) { + + // Check and collect resource signature directory files. + _files, _err := os.ReadDir(resSig.Root) + if _err != nil { + return DirectoryPackage{}, _err + } + + _resPkg := DirectoryPackage{ + Root: resSig.Root, + DependencyFiles: []string{}, + DependencyData: nil, + } + + _resFileDirDeps := []string{} + + // Collete all valid files and/or sub-directory files. + for _, _f := range _files { + + if _f.IsDir() && (resSig.DependencyDepth > 0 || resSig.DependencyDepth == -1) { + // Recurse into valid sub-directory files. + + _resDirSig, _err := MakeDirectorySig(_f.Name(), resSig.DependencyDepth, resSig.DependencyPattern) + if _err != nil { + return DirectoryPackage{}, _err + } + + _resDirPkg, _err := MakeDirectoryPkg(_resDirSig) + if _err != nil { + return DirectoryPackage{}, _err + } + + _resFileDirDeps = append(_resFileDirDeps, _resDirPkg.DependencyFiles...) + + } else if resSig.DependencyPattern != nil && resSig.DependencyPattern.MatchString(_f.Name()) { + // Add files that match pattern to dependency list. + + _resPkg.DependencyFiles = append(_resPkg.DependencyFiles, filepath.Join(_resPkg.Root, _f.Name())) + } + } + + // Include any sub-directory file dependencies. + _resPkg.DependencyFiles = append(_resPkg.DependencyFiles, _resFileDirDeps...) + + log.Printf("INFO\tMakeDirectoryPkg:%v\n", _resPkg) + return _resPkg, nil +} + +func GetYamlContent(yamlObjectId string, dataContainerReference any) { + + _byteBuffer := bytes.NewBufferString(yamlObjectId) + + _decoder := yaml.NewDecoder(_byteBuffer, yaml.ReferenceDirs("sys")) + if _err := _decoder.Decode(dataContainerReference); _err != nil { + // NOTE: Not a sustainable solution for error handling long-term. + // TODO: Implement error handling to gracefully exit during runtime. + log.Panicln("__PANIC\tmain:GetYamlContent:" + _err.Error()) + } + + log.Printf("DONE\tmain:GetYamlContent:%v\n", dataContainerReference) +} + +func Init() { + + //// PULL SYSTEM INFO FROM YAML + + var _mfilesys struct { + FileSystemInfo struct { + RootDir string + WebDir string + } + } + GetYamlContent("filesysteminfo: *fs\n", &_mfilesys) + + Paths.RootDirectory = _mfilesys.FileSystemInfo.RootDir + Paths.WebDirectory = _mfilesys.FileSystemInfo.WebDir + + //// GET GLOBAL DIRECTORY RESOURCES + + _globalSig, _err := MakeDirectorySig(filepath.Join(Paths.WebDirectory, "/global"), 0, FilePatternHTML) + if _err != nil { + log.Panicf("__PANIC\tnetwork:Init:MakeDirectorySig:%s", _err) + } + + GlobalPkg, _err = MakeDirectoryPkg(_globalSig) + if _err != nil { + log.Panicf("__PANIC\tnetwork:Init:MakeDirectoryPkg:%s", _err) + } +} diff --git a/src/miki/miki.go b/src/miki/miki.go @@ -1,204 +1,13 @@ package main import ( - "bytes" - // "context" - "fmt" - "html/template" - "log" - "net/http" - "os" - "path/filepath" - "regexp" - - "github.com/goccy/go-yaml" - // "go.mongodb.org/mongo-driver/v2/mongo" - // "go.mongodb.org/mongo-driver/v2/mongo/options" + mfs "miki/src/filesystem" + mnw "miki/src/network" ) -type DirectorySignature struct { - root string // The root directoy of the resource. - dependencyDepth int // The folder search depth of the resource. -1=inf, 0=single, >0=n-depth - dependencyPattern *regexp.Regexp // The pattern of valid resource dependency files. -} - -func MakeDirectorySig(dir string, depth int, pattern *regexp.Regexp) (DirectorySignature, error) { - - if dir == "" || depth < -1 || pattern == nil { - return DirectorySignature{}, fmt.Errorf("invalid directory signature (%s, %d, %s)", dir, depth, pattern) - } - - if _, _err := os.Stat(dir); _err != nil { - return DirectorySignature{}, _err - } - - return DirectorySignature{dir, depth, pattern}, nil -} - -type DirectoryPackage struct { - root string // The root directory of the resource. - dependencyFiles []string // The set of valid resource files. - dependencyData IDirectoryData // Any relevant resource data. -} - -type IDirectoryData interface { -} - -func MakeDirectoryPkg(resSig DirectorySignature) (DirectoryPackage, error) { - - // Check and collect resource signature directory files. - _files, _err := os.ReadDir(resSig.root) - if _err != nil { - return DirectoryPackage{}, _err - } - - _resPkg := DirectoryPackage{ - root: resSig.root, - dependencyFiles: []string{}, - dependencyData: nil, - } - - _resFileDirDeps := []string{} - - // Collete all valid files and sub directory files. - for _, _f := range _files { - - if _f.IsDir() && (resSig.dependencyDepth > 0 || resSig.dependencyDepth == -1) { - // Recurse into valid directory files. - - _resDirSig, _err := MakeDirectorySig(_f.Name(), resSig.dependencyDepth, resSig.dependencyPattern) - if _err != nil { - return DirectoryPackage{}, _err - } - - _resDirPkg, _err := MakeDirectoryPkg(_resDirSig) - if _err != nil { - return DirectoryPackage{}, _err - } - - _resFileDirDeps = append(_resFileDirDeps, _resDirPkg.dependencyFiles...) - - } else if resSig.dependencyPattern != nil && resSig.dependencyPattern.MatchString(_f.Name()) { - // Add files that match pattern to dependency list. - _resPkg.dependencyFiles = append(_resPkg.dependencyFiles, filepath.Join(_resPkg.root, _f.Name())) - } - } - - // Add any sub directory file dependencies. - _resPkg.dependencyFiles = append(_resPkg.dependencyFiles, _resFileDirDeps...) - - return _resPkg, nil -} - -func GetYamlContent(yamlObjectId string, dataContainerReference any) { - - _byteBuffer := bytes.NewBufferString(yamlObjectId) - - _decoder := yaml.NewDecoder(_byteBuffer, yaml.ReferenceDirs("sys")) - if _err := _decoder.Decode(dataContainerReference); _err != nil { - // NOTE: Not a sustainable solution for error handling long-term. - // TODO: Implement error handling to gracefully exit during runtime. - log.Panicln("__PANIC\tmain:GetYamlContent:" + _err.Error()) - } - - log.Printf("DONE\tmain:GetYamlContent:%v\n", dataContainerReference) -} - func main() { + mfs.Init() - ////////// PULL SYSTEM INFO FROM YAML ////////// - - var _mfilesys struct { - FileSystemInfo struct { - RootDir string - WebDir string - } - } - GetYamlContent("filesysteminfo: *fs\n", &_mfilesys) - - var _msrvinfo struct { - ServerInfo struct { - Port string - SslPath string - CertFile string - KeyFile string - } - } - GetYamlContent("serverinfo: *si\n", &_msrvinfo) - - ////////// CHECK FOR VALID CERT INFO ////////// - - _tls_cert_path := filepath.Join(_msrvinfo.ServerInfo.SslPath, _msrvinfo.ServerInfo.CertFile) - if _, err := os.Stat(_tls_cert_path); err != nil { - log.Panicf("__PANIC\tmain:%s", err) - } - - _tls_key_path := filepath.Join(_msrvinfo.ServerInfo.SslPath, _msrvinfo.ServerInfo.KeyFile) - if _, err := os.Stat(_tls_key_path); err != nil { - log.Panicf("__PANIC\tmain:%s", err) - } - - ////////// SET UP SERVER MUX ////////// - - _mux := http.NewServeMux() - - _mux.Handle("/web/", http.StripPrefix("/web/", http.FileServer(http.Dir(_mfilesys.FileSystemInfo.WebDir)))) - - _mux.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) { - // log.Printf("CALL\tmain:mux.HandleFunc:%s\n", r.URL) - http.ServeFile(w, r, _mfilesys.FileSystemInfo.WebDir+"/global/favicon.ico") - // log.Printf("DONE\tmain:mux.HandleFunc:%s\n", r.URL) - }) - - _mux.HandleFunc("/home", func(w http.ResponseWriter, r *http.Request) { - log.Printf("CALL\tmain:mux.HandleFunc:%s\n", r.URL) - - // Produce URL path to directory relation. - _r, _err := MakeDirectorySig(_mfilesys.FileSystemInfo.WebDir+"/home", 0, regexp.MustCompile("^([a-zA-Z0-9.]+).html$")) - if _err != nil { - log.Printf("_ERROR\tmain:HandleFunc(\"/\"):MakeResourceSig():%s\n", _err) - http.NotFound(w, r) - return - } - - // Collect HTML template files from directory. - _rPkg, _err := MakeDirectoryPkg(_r) - if _err != nil { - log.Printf("_ERROR\tmain:HandleFunc(\"/\"):MakeResourcePkg():%s\n", _err) - http.NotFound(w, r) - return - } - - _tmpl, _err := template.ParseFiles(_rPkg.dependencyFiles...) - if _err != nil { - log.Printf("_ERROR\tmain:HandleFunc(\"/\"):MakeResourcePkg():%s\n", _err) - http.Error(w, "_ERROR:HandleFunc(\"/\"):template.ParseFiles()", 500) - return - } - - if _err = _tmpl.ExecuteTemplate(w, "index.html", _rPkg.dependencyData); _err != nil { - log.Printf("_ERROR\tmain:HandleFunc(\"/\"):MakeResourcePkg():%s\n", _err) - http.Error(w, "_ERROR:HandleFunc(\"/\"):template.ExecuteTemplate()", 500) - return - } - - log.Printf("DONE\tmain:mux.HandleFunc:%s\n", r.URL) - }) - - _mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - // log.Printf("CALL\tmain:mux.HandleFunc:%s\n", r.URL) - if r.URL.Path == "/" { - http.Redirect(w, r, "/home", http.StatusMovedPermanently) - return - } else { - http.NotFound(w, r) - } - // log.Printf("DONE\tmain:mux.HandleFunc:%s\n", r.URL) - }) - - ////////// RUN SERVERS ////////// - - if _err := http.ListenAndServeTLS(":"+_msrvinfo.ServerInfo.Port, _tls_cert_path, _tls_key_path, _mux); _err != nil { - fmt.Printf("_ERROR\tmain():ListenAndServeTLS:%s\n", _err) - } + mnw.Init() + mnw.Exec() } diff --git a/src/network/network.go b/src/network/network.go @@ -0,0 +1,121 @@ +package network + +import ( + "fmt" + "log" + "net/http" + "os" + "path/filepath" + "text/template" + + mfs "miki/src/filesystem" +) + +var serverInfo struct { + port string + sslPath string + certFile string + keyFile string +} + +var mux *http.ServeMux + +func Init() { + + //// GET SERVER INFO + + var _msrvinfo struct { + ServerInfo struct { + Port string + SslPath string + CertFile string + KeyFile string + } + } + mfs.GetYamlContent("serverinfo: *si\n", &_msrvinfo) + serverInfo.port = _msrvinfo.ServerInfo.Port + serverInfo.sslPath = _msrvinfo.ServerInfo.SslPath + serverInfo.certFile = filepath.Join(serverInfo.sslPath, _msrvinfo.ServerInfo.CertFile) + serverInfo.keyFile = filepath.Join(serverInfo.sslPath, _msrvinfo.ServerInfo.KeyFile) + + //// CHECK FOR VALID CERT INFO + + _tls_cert_path := filepath.Join(_msrvinfo.ServerInfo.SslPath, _msrvinfo.ServerInfo.CertFile) + if _, err := os.Stat(_tls_cert_path); err != nil { + log.Panicf("__PANIC\tmain:%s", err) + } + + _tls_key_path := filepath.Join(_msrvinfo.ServerInfo.SslPath, _msrvinfo.ServerInfo.KeyFile) + if _, err := os.Stat(_tls_key_path); err != nil { + log.Panicf("__PANIC\tmain:%s", err) + } + + //// SET UP SERVER MUX + + mux = http.NewServeMux() + + mux.Handle("/web/", http.StripPrefix("/web/", http.FileServer(http.Dir(mfs.Paths.WebDirectory)))) + + mux.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) { + // log.Printf("CALL\tmain:mux.HandleFunc:%s\n", r.URL) + http.ServeFile(w, r, mfs.Paths.WebDirectory+"/global/favicon.ico") + // log.Printf("DONE\tmain:mux.HandleFunc:%s\n", r.URL) + }) + + mux.HandleFunc("/home", func(w http.ResponseWriter, r *http.Request) { + log.Printf("CALL\tmain:mux.HandleFunc:%s\n", r.URL) + + // Produce URL path to directory relation. + _r, _err := mfs.MakeDirectorySig(mfs.Paths.WebDirectory+"/home", 0, mfs.FilePatternHTML) + if _err != nil { + log.Printf("_ERROR\tmain:HandleFunc(\"/\"):MakeResourceSig():%s\n", _err) + http.NotFound(w, r) + return + } + + // Collect HTML template files from directory. + _rPkg, _err := mfs.MakeDirectoryPkg(_r) + if _err != nil { + log.Printf("_ERROR\tmain:HandleFunc(\"/\"):MakeResourcePkg():%s\n", _err) + http.NotFound(w, r) + return + } + + _rPkg.DependencyFiles = append(_rPkg.DependencyFiles, mfs.GlobalPkg.DependencyFiles...) + + _tmpl, _err := template.ParseFiles(_rPkg.DependencyFiles...) + if _err != nil { + log.Printf("_ERROR\tmain:HandleFunc(\"/\"):MakeResourcePkg():%s\n", _err) + http.Error(w, "_ERROR:HandleFunc(\"/\"):template.ParseFiles()", 500) + return + } + + if _err = _tmpl.ExecuteTemplate(w, "index.html", _rPkg.DependencyData); _err != nil { + log.Printf("_ERROR\tmain:HandleFunc(\"/\"):MakeResourcePkg():%s\n", _err) + http.Error(w, "_ERROR:HandleFunc(\"/\"):template.ExecuteTemplate()", 500) + return + } + + log.Printf("DONE\tmain:mux.HandleFunc:%s\n", r.URL) + }) + + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + // log.Printf("CALL\tmain:mux.HandleFunc:%s\n", r.URL) + if r.URL.Path == "/" { + http.Redirect(w, r, "/home", http.StatusMovedPermanently) + return + } else { + http.NotFound(w, r) + } + // log.Printf("DONE\tmain:mux.HandleFunc:%s\n", r.URL) + }) +} + +func Exec() { + + //// RUN SERVER + + if _err := http.ListenAndServeTLS(":"+serverInfo.port, serverInfo.certFile, serverInfo.keyFile, mux); _err != nil { + fmt.Printf("_ERROR\tmain():ListenAndServeTLS:%s\n", _err) + } +} diff --git a/web/home/script.js b/web/global/script.js diff --git a/web/home/styles.css b/web/global/styles.css diff --git a/web/home/index.html b/web/home/index.html @@ -4,8 +4,8 @@ <head> <title>Miki</title> <meta name="viewport" charset="utf-8" content="width=device-width, initial-scale=1.0" /> - <link rel="stylesheet" type="text/css" href="/web/home/styles.css" /> - <script src="/web/home/script.js" defer></script> + <link rel="stylesheet" type="text/css" href="/web/global/styles.css" /> + <script src="/web/global/styles.css" defer></script> </head> <body>