adding a delta logger facility for easier recovery in case of bugs
This commit is contained in:
@@ -10,6 +10,8 @@ type Document struct {
|
|||||||
lines []string
|
lines []string
|
||||||
deltas []Delta
|
deltas []Delta
|
||||||
clients []*Client
|
clients []*Client
|
||||||
|
|
||||||
|
logger *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeltaHandler interface {
|
type DeltaHandler interface {
|
||||||
|
|||||||
+86
-11
@@ -1,6 +1,9 @@
|
|||||||
package acedoc
|
package acedoc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -15,8 +18,8 @@ func (d *Document) Client(h DeltaHandler) *Client {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
dls := c.pullDeltas()
|
dls, ok := c.pullDeltas()
|
||||||
if dls != nil && c.handler != nil {
|
if len(dls) > 0 && c.handler != nil {
|
||||||
go func() {
|
go func() {
|
||||||
err := c.handler.Handle(dls)
|
err := c.handler.Handle(dls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -29,6 +32,9 @@ func (d *Document) Client(h DeltaHandler) *Client {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -40,6 +46,12 @@ func (d *Document) Client(h DeltaHandler) *Client {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Document) Close() {
|
||||||
|
if d.logger != nil {
|
||||||
|
d.logger.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Document) removeClient(c *Client) {
|
func (d *Document) removeClient(c *Client) {
|
||||||
d.mtx.Lock()
|
d.mtx.Lock()
|
||||||
defer d.mtx.Unlock()
|
defer d.mtx.Unlock()
|
||||||
@@ -104,7 +116,7 @@ func (c *Client) PushDeltas(d ...Delta) error {
|
|||||||
return c.doc.Apply(ds...)
|
return c.doc.Apply(ds...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) pullDeltas() []Delta {
|
func (c *Client) pullDeltas() ([]Delta, bool) {
|
||||||
maxSize := c.maxDeltaBucket
|
maxSize := c.maxDeltaBucket
|
||||||
if maxSize == 0 {
|
if maxSize == 0 {
|
||||||
maxSize = 50
|
maxSize = 50
|
||||||
@@ -120,26 +132,89 @@ func (c *Client) pullDeltas() []Delta {
|
|||||||
|
|
||||||
select {
|
select {
|
||||||
case d, ok = <-c.ch:
|
case d, ok = <-c.ch:
|
||||||
|
if !ok {
|
||||||
|
return ds, false
|
||||||
|
}
|
||||||
case <-timer:
|
case <-timer:
|
||||||
return ds
|
return ds, true
|
||||||
}
|
|
||||||
|
|
||||||
timer = time.After(timeout)
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return ds
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.Equal(Delta{}) {
|
if d.Equal(Delta{}) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.source == c {
|
if d.source == c {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timer = time.After(timeout)
|
||||||
|
|
||||||
ds = append(ds, d)
|
ds = append(ds, d)
|
||||||
if len(ds) == maxSize {
|
if len(ds) == maxSize {
|
||||||
return ds
|
return ds, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Document) LogToFile(filename string) error {
|
||||||
|
if d.logger != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var f *os.File
|
||||||
|
var err error
|
||||||
|
var mtx sync.Mutex
|
||||||
|
var closeTimer *time.Timer
|
||||||
|
|
||||||
|
err = os.MkdirAll(path.Dir(filename), 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
getFile := func() {
|
||||||
|
if f != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f, err = os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
||||||
|
closeTimer.Reset(1 * time.Minute)
|
||||||
|
}
|
||||||
|
|
||||||
|
closeFile := func() {
|
||||||
|
mtx.Lock()
|
||||||
|
defer mtx.Unlock()
|
||||||
|
|
||||||
|
if f != nil {
|
||||||
|
err = f.Close()
|
||||||
|
f = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closeTimer = time.AfterFunc(1*time.Minute, closeFile)
|
||||||
|
|
||||||
|
getFile()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.logger = d.Client(DeltaHandlerFunc(func(dls []Delta) error {
|
||||||
|
mtx.Lock()
|
||||||
|
defer mtx.Unlock()
|
||||||
|
|
||||||
|
getFile()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
enc := json.NewEncoder(f)
|
||||||
|
for _, dl := range dls {
|
||||||
|
err = enc.Encode(dl)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -196,9 +196,7 @@ func (d *Document) Apply(dls ...Delta) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("delta does not apply to document: %v", err)
|
return fmt.Errorf("delta does not apply to document: %v", err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for _, dl := range dls {
|
|
||||||
switch dl.Action {
|
switch dl.Action {
|
||||||
case DeltaInsert:
|
case DeltaInsert:
|
||||||
d.applyInsert(dl)
|
d.applyInsert(dl)
|
||||||
|
|||||||
Verwijs in nieuw issue
Block a user