123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- // Simpliest server
- package main
- //go:generate folder2go -handler assets binAssets
- import (
- "errors"
- "fmt"
- "io/ioutil"
- "net"
- "net/http"
- "os"
- "path/filepath"
- "strings"
- "text/template"
- "dev.hexasoftware.com/hxs/httpServe/binAssets"
- "dev.hexasoftware.com/stdio/wsrpc"
- "github.com/fsnotify/fsnotify"
- "github.com/gohxs/prettylog"
- "github.com/gohxs/webu"
- "github.com/gohxs/webu/chain"
- "github.com/shurcooL/github_flavored_markdown/gfmstyle"
- )
- var (
- log = prettylog.New("httpServe")
- tmpl = template.New("")
- )
- func main() {
- prettylog.Global()
- mux := http.NewServeMux()
- c := chain.New(webu.ChainLogger(prettylog.New("serve")))
- mux.HandleFunc("/.httpServe/_reload/", wsrpc.New(wsrpcClient).ServeHTTP)
- mux.Handle("/.httpServe/gfm/", http.StripPrefix("/.httpServe/gfm", http.FileServer(gfmstyle.Assets)))
- mux.HandleFunc("/.httpServe/", binAssets.AssetHandleFunc)
- // Only logs this
- mux.HandleFunc("/", c.Build(fileServe))
- // Load templates from binAssets
- tmplFiles := []string{
- "tmpl/MD.tmpl",
- "tmpl/Folder.tmpl",
- }
- for _, v := range tmplFiles {
- _, err := tmpl.New(v).Parse(string(binAssets.Data[v]))
- if err != nil {
- log.Fatal("Internal error, loading templates")
- }
- }
- var port = 8080
- for {
- addr := fmt.Sprintf(":%d", port)
- listener, err := net.Listen("tcp", addr)
- if err != nil {
- log.Println("Err opening", port, err)
- port++
- log.Println("Trying port", port)
- continue
- }
- log.Println("Listening with port:", port)
- http.Serve(listener, mux)
- }
- //http.ListenAndServe(":8080", http.FileServer(http.Dir('.')))
- }
- func wsrpcClient(ctx *wsrpc.ClientCtx) {
- log.Println("Ws connected")
- watcher, err := fsnotify.NewWatcher() // watcher per socket
- if err != nil {
- return
- }
- defer watcher.Close()
- ctx.Define("watch", func(params ...interface{}) (interface{}, error) {
- toWatch, ok := params[0].(string)
- if !ok {
- return nil, errors.New("Param invalid")
- }
- absFile, err := filepath.Abs(toWatch[1:])
- if err != nil {
- return nil, err
- }
- err = watcher.Add(absFile) // remove root '/' prefix
- if err != nil {
- log.Println("Error watching", err)
- }
- // Request to watch something?
- return true, nil
- })
- for {
- select {
- case event := <-watcher.Events:
- if event.Op&fsnotify.Remove != 0 {
- ctx.Call("reload")
- }
- case <-ctx.Done():
- return
- }
- }
- }
- func handleMarkDown(w http.ResponseWriter, r *http.Request, path string) error {
- fileData, err := ioutil.ReadFile(path)
- if err != nil {
- return err
- }
- err = tmpl.ExecuteTemplate(w, "tmpl/MD.tmpl", map[string]interface{}{
- "path": path,
- "content": string(fileData),
- })
- return err
- }
- func handleFolder(w http.ResponseWriter, r *http.Request, path string) error {
- res, err := ioutil.ReadDir(path)
- if err != nil {
- return err
- }
- err = tmpl.ExecuteTemplate(w, "tmpl/Folder.tmpl", map[string]interface{}{
- "path": path,
- "content": res,
- })
- return err
- }
- func fileServe(w http.ResponseWriter, r *http.Request) {
- path := r.URL.Path[1:]
- if path == "" {
- path = "index.html"
- if _, err := os.Stat(path); os.IsNotExist(err) {
- path = "."
- }
- }
- if strings.Contains(path, "..") {
- http.ServeFile(w, r, path)
- }
- //log.Printf("%s - %s", r.Method, r.URL.Path)
- fstat, err := os.Stat(path)
- if err != nil {
- webu.WriteStatus(w, http.StatusNotFound)
- return
- }
- if fstat.IsDir() {
- err := handleFolder(w, r, path)
- if err != nil {
- webu.WriteStatus(w, http.StatusInternalServerError, err)
- }
- return
- }
- if filepath.Ext(path) == ".md" {
- err := handleMarkDown(w, r, path)
- if err != nil {
- webu.WriteStatus(w, http.StatusInternalServerError, err)
- }
- return
- }
- http.ServeFile(w, r, path)
- }
|