Oh it's so sexy
4 files changed, 109 insertions(+), 36 deletions(-)

M resources.go
M server.go
M static/js.js
M watch.go
M resources.go +1 -1
@@ 23,7 23,7 @@ var (
 
 type Request struct {
     Subscribe       bool
-    Path            string
+    Path            WebPath
 }
 
 type Error struct {

          
M server.go +79 -26
@@ 23,7 23,7 @@ type GoquiturHandler struct {
     sublock         *sync.Mutex
     urlsubs          map[WebPath][]*websocket.Conn
     // what was I supposed to be using this for again?
-    suburls          map[*websocket.Conn][]WebPath
+    //suburls          map[*websocket.Conn][]WebPath
 }
 
 func NewGoquiturHandler(watchdir string) (*GoquiturHandler, error) {

          
@@ 46,7 46,7 @@ func NewGoquiturHandler(watchdir string)
         watcher: watcher,
         sublock: new(sync.Mutex),
         urlsubs: make(map[WebPath][]*websocket.Conn),
-        suburls: make(map[*websocket.Conn][]WebPath),
+        //suburls: make(map[*websocket.Conn][]WebPath),
     }
     h.ServeMux.Handle("/", http.FileServer(http.Dir("static")))
     h.ServeMux.Handle("/ws", websocket.Handler(h.serveWS))

          
@@ 73,7 73,13 @@ func (h *GoquiturHandler) LocationFromWe
 }
 
 func (h *GoquiturHandler) LocationFromFilePath(path FSPath) (*Location, error) {
+    // this could use some work ... and unit testing, sheesh ...
     webpath, err := filepath.Rel(h.watchdir, string(path))
+    if webpath == "." {
+        webpath = "/"
+    } else {
+        webpath = "/" + webpath
+    }
     if err != nil {
         return nil, err
     }

          
@@ 89,6 95,54 @@ func (h *GoquiturHandler) Subscribers(pa
     return make([]*websocket.Conn, 0)
 }
 
+func (h *GoquiturHandler) Subscribe(ws *websocket.Conn, path WebPath) {
+    h.sublock.Lock()
+    defer h.sublock.Unlock()
+
+    subs, ok := h.urlsubs[path]
+    if ok == false {
+        subs = make([]*websocket.Conn, 0)
+    }
+    h.urlsubs[path] = append(subs, ws)
+
+    //urls, ok := h.suburls[ws]
+    //if ok == false {
+    //    urls = make([]WebPath, 0)
+    //}
+    //h.suburls[ws] = append(urls, path)
+}
+
+func (h *GoquiturHandler) Unsubscribe(ws *websocket.Conn, path WebPath) {
+    h.sublock.Lock()
+    defer h.sublock.Unlock()
+
+    // Remove ws from subs at loc.WebPath
+    subs, ok := h.urlsubs[path]
+    if ok {
+        for i := 0; i < len(subs); {
+            if subs[i] == ws {
+                subs = append(subs[:i], subs[i+1:]...)
+            } else {
+                i++
+            }
+        }
+        h.urlsubs[path] = subs
+    }
+
+    //// Remove path from subscribed paths for this URL
+    //urls, ok := h.suburls[ws]
+    //if ok == false {
+    //    for i := 0; i < len(urls) {
+    //        if urls[i] == path {
+    //            urls = append(urls[:i], urls[i+1:]...)
+    //        } else {
+    //            i++
+    //        }
+    //    }
+    //    h.suburls[ws] = append(urls, path)
+    //}
+}
+
 func (h *GoquiturHandler) handleEvents(evchan <-chan *Event, errchan <-chan error) {
     for {
         select {

          
@@ 107,9 161,14 @@ func (h *GoquiturHandler) handleEvents(e
                 continue
             }
 
+            log.Println(h.urlsubs)
+            log.Println(loc.WebPath)
+
             switch ev.Type {
             case EventCreate:
+                fallthrough
             case EventModify:
+                fallthrough
             case EventDelete:
                 var data []byte
                 for _, sub := range h.Subscribers(loc.WebPath) {

          
@@ 138,7 197,9 @@ func (h *GoquiturHandler) handleEvents(e
                         }
                     }
                     go func() {
+                        log.Println("gonna write data for event to", sub)
                         _, err = sub.Write(data)
+                        log.Println("wrote data", sub, err)
                         if err != nil {
                             log.Println("Error writing to a client:", err)
                             // todo, remove subscriber?

          
@@ 193,32 254,24 @@ func (h *GoquiturHandler) serveOneWS(ws 
         })
     }
 
-    // Get the payload
-    payload, err := getPayload(validpath)
-    if err != nil {
-        return websocket.JSON.Send(ws, &Error{
-            Message: "Could not read resource",
-            Details: err.Error(),
-        })
+    var payload interface{}
+
+    if r.Subscribe {
+        // Get the payload
+        payload, err = getPayload(validpath)
+        if err != nil {
+            return websocket.JSON.Send(ws, &Error{
+                Message: "Could not read resource",
+                Details: err.Error(),
+            })
+        }
+
+        h.Subscribe(ws, r.Path)
+    } else {
+        h.Unsubscribe(ws, r.Path)
     }
 
-    // Subscribe to the resource
-    h.sublock.Lock()
-    defer h.sublock.Unlock()
-
-    subs, ok := h.urlsubs[loc.WebPath]
-    if ok == false {
-        subs = make([]*websocket.Conn, 0)
-    }
-    h.urlsubs[loc.WebPath] = append(subs, ws)
-
-    urls, ok := h.suburls[ws]
-    if ok == false {
-        urls = make([]WebPath, 0)
-    }
-    h.suburls[ws] = append(urls, loc.WebPath)
-
-    // Send the resource
+    log.Println("subscribing:", ws, loc.WebPath, r.Subscribe)
     return websocket.JSON.Send(ws, &Message{
         Path: loc.WebPath,
         Payload: payload,

          
M static/js.js +1 -0
@@ 7,6 7,7 @@ var GoquiturConn = function() {
 
     that.open = function(addr) {
         that.ws = new WebSocket(addr);
+        console.log("this is a good sign");
         that.ws.onopen    = function(e) { that.trigger("open", e) };
         that.ws.onerror   = function(e) { that.trigger("error", e) };
         that.ws.onclose   = function(e) { that.trigger("close", e) };

          
M watch.go +28 -9
@@ 23,19 23,38 @@ func processLoop(w *fsnotify.Watcher, ev
                 continue
             }
 
-            ev := new(Event)
-            ev.Path = path
-            if fsev.IsDelete() || fsev.IsRename() {
-                ev.Type = EventDelete
-            } else if fsev.IsModify() {
-                ev.Type = EventModify
+            if fsev.IsModify() {
+                evchan <- &Event{
+                    Type: EventModify,
+                    Path: path,
+                }
+            } else if fsev.IsDelete() || fsev.IsRename() {
+                evchan <- &Event{
+                    Type: EventDelete,
+                    Path: path,
+                }
+                parent := filepath.Dir(path)
+                if parent != "" && parent != path {
+                    evchan <- &Event{
+                        Type: EventModify,
+                        Path: parent,
+                    }
+                }
             } else if fsev.IsCreate() {
-                ev.Type = EventCreate
+                evchan <- &Event{
+                    Type: EventCreate,
+                    Path: path,
+                }
+                parent := filepath.Dir(path)
+                if parent != "" && parent != path {
+                    evchan <- &Event{
+                        Type: EventModify,
+                        Path: parent,
+                    }
+                }
             } else {
                 log.Println("unhandled event, don't know what to do with event of this type")
-                continue
             }
-            evchan <- ev
 
         case err := <-w.Error:
             errchan <- err