|
|
@ -4,11 +4,16 @@ import ( |
|
|
|
"errors" |
|
|
|
"errors" |
|
|
|
"fmt" |
|
|
|
"fmt" |
|
|
|
"html/template" |
|
|
|
"html/template" |
|
|
|
|
|
|
|
"io/ioutil" |
|
|
|
"net/http" |
|
|
|
"net/http" |
|
|
|
"os" |
|
|
|
"os" |
|
|
|
"path" |
|
|
|
"path" |
|
|
|
"path/filepath" |
|
|
|
"path/filepath" |
|
|
|
"strings" |
|
|
|
"strings" |
|
|
|
|
|
|
|
"sync" |
|
|
|
|
|
|
|
"sync/atomic" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"git.stephensearles.com/stephen/acedoc" |
|
|
|
|
|
|
|
|
|
|
|
"github.com/gorilla/websocket" |
|
|
|
"github.com/gorilla/websocket" |
|
|
|
"github.com/mholt/caddy" |
|
|
|
"github.com/mholt/caddy" |
|
|
@ -31,11 +36,32 @@ type CaddyHugo struct { |
|
|
|
ServerType string |
|
|
|
ServerType string |
|
|
|
Site *httpserver.SiteConfig |
|
|
|
Site *httpserver.SiteConfig |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Docs map[string]*acedoc.Document |
|
|
|
|
|
|
|
mtx sync.Mutex |
|
|
|
|
|
|
|
|
|
|
|
authorTmpl, adminTmpl, editTmpl *template.Template |
|
|
|
authorTmpl, adminTmpl, editTmpl *template.Template |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ltime uint64 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (ch *CaddyHugo) ObserveLTime(ltime uint64) uint64 { |
|
|
|
|
|
|
|
ch.mtx.Lock() |
|
|
|
|
|
|
|
defer ch.mtx.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ch.ltime < ltime { |
|
|
|
|
|
|
|
ch.ltime = ltime |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ch.LTime() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (ch *CaddyHugo) LTime() uint64 { |
|
|
|
|
|
|
|
return atomic.AddUint64(&ch.ltime, 1) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (ch CaddyHugo) Setup(c *caddy.Controller) error { |
|
|
|
func (ch *CaddyHugo) Setup(c *caddy.Controller) error { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ch.Docs = make(map[string]*acedoc.Document) |
|
|
|
ch.Site = httpserver.GetConfig(c) |
|
|
|
ch.Site = httpserver.GetConfig(c) |
|
|
|
|
|
|
|
|
|
|
|
var err error |
|
|
|
var err error |
|
|
@ -106,7 +132,7 @@ func (ch CaddyHugo) BasePath() string { |
|
|
|
|
|
|
|
|
|
|
|
func (ch CaddyHugo) Admin() httpserver.Handler { |
|
|
|
func (ch CaddyHugo) Admin() httpserver.Handler { |
|
|
|
return httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { |
|
|
|
return httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { |
|
|
|
err := ch.adminTmpl.Execute(w, ch.TmplData(r)) |
|
|
|
err := ch.adminTmpl.Execute(w, ch.TmplData(r, nil)) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
fmt.Println(err) |
|
|
|
fmt.Println(err) |
|
|
|
return http.StatusInternalServerError, err |
|
|
|
return http.StatusInternalServerError, err |
|
|
@ -119,7 +145,7 @@ func (ch CaddyHugo) Admin() httpserver.Handler { |
|
|
|
|
|
|
|
|
|
|
|
func (ch CaddyHugo) AuthorHome() httpserver.Handler { |
|
|
|
func (ch CaddyHugo) AuthorHome() httpserver.Handler { |
|
|
|
return httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { |
|
|
|
return httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { |
|
|
|
err := ch.authorTmpl.Execute(w, ch.TmplData(r)) |
|
|
|
err := ch.authorTmpl.Execute(w, ch.TmplData(r, nil)) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
fmt.Println(err) |
|
|
|
fmt.Println(err) |
|
|
|
return http.StatusInternalServerError, err |
|
|
|
return http.StatusInternalServerError, err |
|
|
@ -129,16 +155,23 @@ func (ch CaddyHugo) AuthorHome() httpserver.Handler { |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (ch CaddyHugo) Edit(c *caddy.Controller) httpserver.Handler { |
|
|
|
func (ch *CaddyHugo) Edit(c *caddy.Controller) httpserver.Handler { |
|
|
|
return httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { |
|
|
|
return httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { |
|
|
|
if r.URL.Path == "/hugo/edit/new" { |
|
|
|
if r.URL.Path == "/hugo/edit/new" { |
|
|
|
return ch.NewContent(w, r) |
|
|
|
return ch.NewContent(w, r) |
|
|
|
} |
|
|
|
} |
|
|
|
if r.URL.Path == "/hugo/edit/websocket" { |
|
|
|
|
|
|
|
|
|
|
|
if r.Header.Get("Upgrade") == "websocket" { |
|
|
|
return ch.DeltaWebsocket(w, r) |
|
|
|
return ch.DeltaWebsocket(w, r) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
err := ch.editTmpl.Execute(w, ch.TmplData(r)) |
|
|
|
doc, err := ch.Doc(r) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
fmt.Println(err) |
|
|
|
|
|
|
|
return http.StatusNotFound, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
err = ch.editTmpl.Execute(w, ch.TmplData(r, doc)) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
|
|
|
|
fmt.Println(err) |
|
|
|
fmt.Println(err) |
|
|
@ -149,7 +182,27 @@ func (ch CaddyHugo) Edit(c *caddy.Controller) httpserver.Handler { |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (ch CaddyHugo) DeltaWebsocket(w http.ResponseWriter, r *http.Request) (int, error) { |
|
|
|
func (ch *CaddyHugo) Doc(r *http.Request) (*acedoc.Document, error) { |
|
|
|
|
|
|
|
ch.mtx.Lock() |
|
|
|
|
|
|
|
defer ch.mtx.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
name := r.URL.Path[len("/hugo/edit/"):] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_, ok := ch.Docs[name] |
|
|
|
|
|
|
|
if !ok { |
|
|
|
|
|
|
|
fmt.Println("opening", name) |
|
|
|
|
|
|
|
contents, err := ioutil.ReadFile(name) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return nil, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ch.Docs[name] = acedoc.NewString(string(contents)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ch.Docs[name], nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (ch *CaddyHugo) DeltaWebsocket(w http.ResponseWriter, r *http.Request) (int, error) { |
|
|
|
var upgrader = websocket.Upgrader{ |
|
|
|
var upgrader = websocket.Upgrader{ |
|
|
|
ReadBufferSize: 1024, |
|
|
|
ReadBufferSize: 1024, |
|
|
|
WriteBufferSize: 1024, |
|
|
|
WriteBufferSize: 1024, |
|
|
@ -161,16 +214,43 @@ func (ch CaddyHugo) DeltaWebsocket(w http.ResponseWriter, r *http.Request) (int, |
|
|
|
return http.StatusBadRequest, err |
|
|
|
return http.StatusBadRequest, err |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
doc, err := ch.Doc(r) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
fmt.Println(err) |
|
|
|
|
|
|
|
return http.StatusBadRequest, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
client := doc.Client(acedoc.DeltaHandlerFunc(func(ds []acedoc.Delta) error { |
|
|
|
|
|
|
|
err := conn.WriteJSON(Message{ |
|
|
|
|
|
|
|
Deltas: ds, |
|
|
|
|
|
|
|
LTime: ch.LTime(), |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
fmt.Println("here", ds, err) |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
})) |
|
|
|
|
|
|
|
|
|
|
|
for { |
|
|
|
for { |
|
|
|
messageType, p, err := conn.ReadMessage() |
|
|
|
var message Message |
|
|
|
|
|
|
|
err := conn.ReadJSON(&message) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return http.StatusBadRequest, err |
|
|
|
return http.StatusBadRequest, err |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fmt.Println(messageType, string(p)) |
|
|
|
ch.ObserveLTime(message.LTime) |
|
|
|
|
|
|
|
fmt.Println(message) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
err = client.PushDeltas(message.Deltas...) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return http.StatusBadRequest, err |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type Message struct { |
|
|
|
|
|
|
|
Deltas []acedoc.Delta `json:"deltas"` |
|
|
|
|
|
|
|
LTime uint64 `json:"ltime"` |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (ch CaddyHugo) NewContent(w http.ResponseWriter, r *http.Request) (int, error) { |
|
|
|
func (ch CaddyHugo) NewContent(w http.ResponseWriter, r *http.Request) (int, error) { |
|
|
|
name := r.FormValue("name") |
|
|
|
name := r.FormValue("name") |
|
|
|
ctype := r.FormValue("type") |
|
|
|
ctype := r.FormValue("type") |
|
|
@ -209,6 +289,6 @@ func (ch CaddyHugo) NewContent(w http.ResponseWriter, r *http.Request) (int, err |
|
|
|
return http.StatusFound, nil |
|
|
|
return http.StatusFound, nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (ch CaddyHugo) TmplData(r *http.Request) interface{} { |
|
|
|
func (ch CaddyHugo) TmplData(r *http.Request, doc *acedoc.Document) interface{} { |
|
|
|
return tmplData{ch.Site, r, ch} |
|
|
|
return tmplData{ch.Site, r, ch, doc} |
|
|
|
} |
|
|
|
} |
|
|
|