Skip to content

Instantly share code, notes, and snippets.

@flysand7
Created October 30, 2021 12:23
Show Gist options
  • Save flysand7/3f8b7d35c85eb65bfc194b0f07623eb9 to your computer and use it in GitHub Desktop.
Save flysand7/3f8b7d35c85eb65bfc194b0f07623eb9 to your computer and use it in GitHub Desktop.
package main;
import (
"fmt"
"net/http"
"io"
"os"
"path"
"path/filepath"
"github.com/fsnotify/fsnotify"
"strings"
"io/ioutil"
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/parser")
const sourcePath = "root";
const watchPath = sourcePath;
const prodStartPath = "prod";
var data_changed = false;
const script=`
<script>setInterval(()=>{var http=new XMLHttpRequest();http.open("GET","http://localhost:8000/~");http.send();http.onreadystatechange=(e)=>{var u=http.responseText;if(u=="1"){location.reload();}};},100);</script>
`
const template=`<!DOCTYPE html><html><head></head><body>{TEXT}</body></html>`
func repositionPath(fn string) string {
i := 0;
for fn[i]!='/'&&fn[i]!='\\'{i++;}
rem := fn[i:];
return prodStartPath+rem;
}
func processSourceFile(fn string) {
ext := path.Ext(fn);
if ext==".md" {
data, err := os.ReadFile(fn);
if err == nil {
target := repositionPath(fn);
target = target[:len(target)-len(ext)]+".html";
/*
func renderHookDropCodeBlock(w io.Writer, node ast.Node, entering bool) (ast.WalkStatus, bool) {
// skip all nodes that are not CodeBlock nodes
if _, ok := node.(*ast.CodeBlock); !ok {
return ast.GoToNext, false
}
// custom rendering logic for ast.CodeBlock. By doing nothing it won't be
// present in the output
return ast.GoToNext, true
}*/
p = parser.NewWithExtensions(extensions);
html:=markdown.ToHTML(data,p,nil);
res := strings.Replace(template, "{TEXT}", string(html), 1);
ioutil.WriteFile(target, []byte(res), 0644)
} else {fmt.Println(err);}
}else {
target := repositionPath(fn);
in, err := os.Open(fn)
if err != nil {
return
}
defer in.Close()
out, err := os.Create(target)
if err != nil {
return
}
defer func() {
cerr := out.Close()
if err == nil {
err = cerr
}
}()
if _, err = io.Copy(out, in); err != nil {
return
}
err = out.Sync()
return
}
}
func requestHandler(w http.ResponseWriter, r *http.Request) {
requestedPath := prodStartPath + r.URL.Path;
// Handle the js input query
if len(r.URL.Path) == 2 && r.URL.Path[1] == '~' {
if data_changed {
fmt.Fprintf(w, "1");
data_changed=false;
}else {
fmt.Fprintf(w, "0");
}
// Handle normal request
} else {
fi, err := os.Stat(requestedPath);
if err == nil {
if fi.Mode().IsDir() {
requestedPath = requestedPath + "/index.html";
}
} else {
fmt.Println(err);
}
data, err := os.ReadFile(requestedPath);
if err!=nil {
message := "Requested resource (" + r.URL.Path + ") not found."
http.Error(w, message, 404);
} else {
replaced:=strings.Replace(string(data), "<head>", "<head>"+script, 1);
fmt.Fprintf(w, "%s", replaced);
}
}
}
var watcher *fsnotify.Watcher
var extensions parser.Extensions;
var p *parser.Parser;
func main() {
extensions=parser.CommonExtensions;
var err error;
watcher, err = fsnotify.NewWatcher()
if err != nil {
fmt.Println("ERROR", err)
}
defer watcher.Close()
if err := filepath.Walk(
watchPath,
func (path string, fi os.FileInfo, err error) error {
if fi.Mode().IsDir() {return watcher.Add(path)};return nil
});
err != nil{
fmt.Println(err)
}
done := make(chan bool)
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
if event.Op&fsnotify.Write == fsnotify.Write {
processSourceFile(event.Name);
data_changed=true
}
case err := <-watcher.Errors:
fmt.Println("watcher err", err)
}
}
}()
go func() {
fmt.Println("Serving on http://localhost:8000!\n");
http.HandleFunc("/", requestHandler);
http.ListenAndServe(":8000", nil);
}()
<-done
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment