|
|
|
@ -12,6 +12,7 @@ import ( |
|
|
|
|
"strings" |
|
|
|
|
"sync" |
|
|
|
|
"sync/atomic" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
"git.stephensearles.com/stephen/acedoc" |
|
|
|
|
|
|
|
|
@ -32,11 +33,16 @@ func init() { |
|
|
|
|
// ... there are others. See the godoc.
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type docref struct { |
|
|
|
|
clients uint |
|
|
|
|
doc *acedoc.Document |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type CaddyHugo struct { |
|
|
|
|
ServerType string |
|
|
|
|
Site *httpserver.SiteConfig |
|
|
|
|
|
|
|
|
|
Docs map[string]*acedoc.Document |
|
|
|
|
docs map[string]*docref |
|
|
|
|
mtx sync.Mutex |
|
|
|
|
|
|
|
|
|
authorTmpl, adminTmpl, editTmpl *template.Template |
|
|
|
@ -61,7 +67,7 @@ func (ch *CaddyHugo) LTime() uint64 { |
|
|
|
|
|
|
|
|
|
func (ch *CaddyHugo) Setup(c *caddy.Controller) error { |
|
|
|
|
|
|
|
|
|
ch.Docs = make(map[string]*acedoc.Document) |
|
|
|
|
ch.docs = make(map[string]*docref) |
|
|
|
|
ch.Site = httpserver.GetConfig(c) |
|
|
|
|
|
|
|
|
|
var err error |
|
|
|
@ -165,13 +171,13 @@ func (ch *CaddyHugo) Edit(c *caddy.Controller) httpserver.Handler { |
|
|
|
|
return ch.DeltaWebsocket(w, r) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
doc, err := ch.Doc(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)) |
|
|
|
|
err = ch.editTmpl.Execute(w, ch.TmplData(r, doc.doc)) |
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
|
|
fmt.Println(err) |
|
|
|
@ -182,13 +188,13 @@ func (ch *CaddyHugo) Edit(c *caddy.Controller) httpserver.Handler { |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (ch *CaddyHugo) Doc(r *http.Request) (*acedoc.Document, error) { |
|
|
|
|
func (ch *CaddyHugo) doc(r *http.Request) (*docref, error) { |
|
|
|
|
ch.mtx.Lock() |
|
|
|
|
defer ch.mtx.Unlock() |
|
|
|
|
|
|
|
|
|
name := r.URL.Path[len("/hugo/edit/"):] |
|
|
|
|
|
|
|
|
|
_, ok := ch.Docs[name] |
|
|
|
|
_, ok := ch.docs[name] |
|
|
|
|
if !ok { |
|
|
|
|
fmt.Println("opening", name) |
|
|
|
|
contents, err := ioutil.ReadFile(name) |
|
|
|
@ -196,10 +202,41 @@ func (ch *CaddyHugo) Doc(r *http.Request) (*acedoc.Document, error) { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ch.Docs[name] = acedoc.NewString(string(contents)) |
|
|
|
|
ref := &docref{doc: acedoc.NewString(string(contents))} |
|
|
|
|
ch.docs[name] = ref |
|
|
|
|
|
|
|
|
|
go func() { |
|
|
|
|
ticker := time.NewTicker(1 * time.Minute) |
|
|
|
|
idleMinutes := 0 |
|
|
|
|
|
|
|
|
|
for { |
|
|
|
|
<-ticker.C |
|
|
|
|
ch.mtx.Lock() |
|
|
|
|
|
|
|
|
|
fmt.Println("saving", name) |
|
|
|
|
err := ioutil.WriteFile(name, []byte(ref.doc.Contents()), 0644) |
|
|
|
|
if err != nil { |
|
|
|
|
fmt.Println("error saving document contents:", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ref.clients == 0 { |
|
|
|
|
idleMinutes++ |
|
|
|
|
if idleMinutes > 10 { |
|
|
|
|
fmt.Println("idle for", idleMinutes, "minutes, quitting") |
|
|
|
|
delete(ch.docs, name) |
|
|
|
|
ch.mtx.Unlock() |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
fmt.Println("idle for", idleMinutes, "minutes") |
|
|
|
|
} else { |
|
|
|
|
idleMinutes = 0 |
|
|
|
|
} |
|
|
|
|
ch.mtx.Unlock() |
|
|
|
|
} |
|
|
|
|
}() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return ch.Docs[name], nil |
|
|
|
|
return ch.docs[name], nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (ch *CaddyHugo) DeltaWebsocket(w http.ResponseWriter, r *http.Request) (int, error) { |
|
|
|
@ -214,21 +251,30 @@ func (ch *CaddyHugo) DeltaWebsocket(w http.ResponseWriter, r *http.Request) (int |
|
|
|
|
return http.StatusBadRequest, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
doc, err := ch.Doc(r) |
|
|
|
|
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 { |
|
|
|
|
client := doc.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 |
|
|
|
|
})) |
|
|
|
|
|
|
|
|
|
ch.mtx.Lock() |
|
|
|
|
doc.clients++ |
|
|
|
|
ch.mtx.Unlock() |
|
|
|
|
|
|
|
|
|
defer func() { |
|
|
|
|
ch.mtx.Lock() |
|
|
|
|
doc.clients-- |
|
|
|
|
ch.mtx.Unlock() |
|
|
|
|
}() |
|
|
|
|
|
|
|
|
|
for { |
|
|
|
|
var message Message |
|
|
|
|
err := conn.ReadJSON(&message) |
|
|
|
@ -237,7 +283,6 @@ func (ch *CaddyHugo) DeltaWebsocket(w http.ResponseWriter, r *http.Request) (int |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ch.ObserveLTime(message.LTime) |
|
|
|
|
fmt.Println(message) |
|
|
|
|
|
|
|
|
|
err = client.PushDeltas(message.Deltas...) |
|
|
|
|
if err != nil { |
|
|
|
|