changeset 1354:59eab70254fa

refactor the rdfdb networking out of (js) SyncedGraph Ignore-this: badbef9ba60ad9f5611fdcdc67c5c34
author Drew Perttula <drewp@bigasterisk.com>
date Sun, 05 Jun 2016 05:01:22 +0000
parents 0de7fd3fed1f
children 9476e97b57fb
files light9/web/graph.coffee
diffstat 1 files changed, 78 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- a/light9/web/graph.coffee	Sun Jun 05 03:53:27 2016 +0000
+++ b/light9/web/graph.coffee	Sun Jun 05 05:01:22 2016 +0000
@@ -39,7 +39,7 @@
         cb({delQuads: [], addQuads: [quad]})
 
 
-jsonPatch = (jsPatch, cb) ->
+toJsonPatch = (jsPatch, cb) ->
   out = {patch: {adds: '', deletes: ''}}
 
   writeDels = (cb) ->
@@ -60,33 +60,50 @@
       cb(JSON.stringify(out))
     )
 
-class window.SyncedGraph
-  # Note that applyPatch is the only method to write to the graph, so
-  # it can fire subscriptions.
+parseJsonPatch = (jsonPatch, cb) ->
+  # note response cb doesn't have an error arg.
+  input = JSON.parse(jsonPatch)
+  patch = {delQuads: [], addQuads: []}
 
-  constructor: (@patchSenderUrl, @prefixes) ->
-    @resetStore()
-    @_watchers = new GraphWatchers()
-    @patchesToSend = []
+  parseAdds = (cb) =>
+    parser = N3.Parser()
+    parser.parse input.patch.adds, (error, quad, prefixes) =>
+                  if (quad)
+                    patch.addQuads.push(quad)
+                  else
+                    cb()
+  parseDels = (cb) =>
+    parser = N3.Parser()
+    parser.parse input.patch.deletes, (error, quad, prefixes) =>
+                  if (quad)
+                    patch.delQuads.push(quad)
+                  else
+                    cb()
+
+  async.parallel([parseAdds, parseDels], ((err) => cb(patch)))
+
+class RdfDbClient
+  # Send and receive patches from rdfdb
+  constructor: (@patchSenderUrl, @clearGraph, @applyPatch) ->
+    @_patchesToSend = []
 
     @_reconnectionTimeout = null
-    @newConnection()
+    @_newConnection()
 
-  resetStore: ->
-    if @graph?
-      @_watchers.graphChanged({addQuads: [], delQuads: @graph.find()})
-    @graph = N3.Store()
-    @_addPrefixes(@prefixes)
+  sendPatch: (patch) ->
+    console.log('queue patch to server ', patchSizeSummary(patch))
+    @_patchesToSend.push(patch)
+    @_continueSending()           
 
-  newConnection: ->
+  _newConnection: ->
     fullUrl = 'ws://' + window.location.host + @patchSenderUrl
     @ws.close() if @ws?
     @ws = new WebSocket(fullUrl)
 
     @ws.onopen = =>
       log('connected to', fullUrl)
-      @resetStore()
-      @pingLoop()
+      @clearGraph()
+      @_pingLoop()
 
     @ws.onerror = (e) =>
       log('ws error ' + e)
@@ -95,41 +112,22 @@
     @ws.onclose = =>
       log('ws close')
       clearTimeout(@_reconnectionTimeout) if @_reconnectionTimeout?
-      @_reconnectionTimeout = setTimeout(@newConnection.bind(@), 1000)
+      @_reconnectionTimeout = setTimeout(@_newConnection.bind(@), 1000)
 
-    @ws.onmessage = (evt) =>
-      if evt.data == 'PONG'
-        return
-      @onMessage(JSON.parse(evt.data))
+    @ws.onmessage = @_onMessage.bind(@)
 
-  pingLoop: () ->
+  _pingLoop: () ->
     if @ws.readyState == @ws.OPEN
       @ws.send('PING')
       
       clearTimeout(@_pingLoopTimeout) if @_pingLoopTimeout?
-      @_pingLoopTimeout = setTimeout(@pingLoop.bind(@), 10000)
-
-  onMessage: (msg) ->
-    log('from rdfdb: ', msg)
-      
-    patch = {delQuads: [], addQuads: []}
+      @_pingLoopTimeout = setTimeout(@_pingLoop.bind(@), 10000)
 
-    parseAdds = (cb) =>
-      parser = N3.Parser()
-      parser.parse msg.patch.adds, (error, quad, prefixes) =>
-                    if (quad)
-                      patch.addQuads.push(quad)
-                    else
-                      cb()
-    parseDels = (cb) =>
-      parser = N3.Parser()
-      parser.parse msg.patch.deletes, (error, quad, prefixes) =>
-                    if (quad)
-                      patch.delQuads.push(quad)
-                    else
-                      cb()
-      
-    async.parallel([parseAdds, parseDels], ((err) => @applyPatch(patch)))
+  _onMessage: (evt) ->
+    msg = evt.data
+    if msg == 'PONG'
+      return
+    parseJsonPatch(msg, @applyPatch.bind(@))
 
   _continueSending: ->
     if @ws.readyState != @ws.OPEN
@@ -140,15 +138,41 @@
     # the dragging cases.
 
     sendOne = (patch, cb) =>
-        jsonPatch(patch, (json) =>
+        toJsonPatch(patch, (json) =>
           log('send patch to server, ' + json.length + ' bytes')
           @ws.send(json)
           cb(null)
       )
 
-    async.eachSeries(@patchesToSend, sendOne, () =>
-        @patchesToSend = []
+    async.eachSeries(@_patchesToSend, sendOne, () =>
+        @_patchesToSend = []
       )
+
+class window.SyncedGraph
+  # Main graph object for a browser to use. Syncs both ways with
+  # rdfdb. Meant to hide the choice of RDF lib, so we can change it
+  # later.
+  # 
+  # Note that _applyPatch is the only method to write to the graph, so
+  # it can fire subscriptions.
+
+  constructor: (@patchSenderUrl, @prefixes) ->
+    # patchSenderUrl is the /syncedGraph path of an rdfdb server.
+    # prefixes can be used in Uri(curie) calls.
+    @_watchers = new GraphWatchers()
+    @clearGraph()
+
+    @_client = new RdfDbClient(@patchSenderUrl, @clearGraph.bind(@),
+                               @_applyPatch.bind(@))
+    
+  clearGraph: ->
+    log('SyncedGraph clear')
+    if @graph?
+      @_applyPatch({addQuads: [], delQuads: @graph.find()})
+
+    # if we had a Store already, this lets N3.Store free all its indices/etc
+    @graph = N3.Store()
+    @_addPrefixes(@prefixes)
     
       
   _addPrefixes: (prefixes) ->
@@ -175,7 +199,7 @@
                   if (quad)
                     patch.addQuads.push(quad)
                   else
-                    @applyPatch(patch)
+                    @_applyPatch(patch)
                     @_addPrefixes(prefixes)
                     cb() if cb
                     
@@ -183,15 +207,13 @@
     [q.subject, q.predicate, q.object, q.graph] for q in @graph.find()
 
   applyAndSendPatch: (patch, cb) ->
-    @applyPatch(patch)
-    console.log('queue patch to server ', patchSizeSummary(patch))
-    @patchesToSend.push(patch)
-    @_continueSending()
+    @_applyPatch(patch)
+    @_client.sendPatch(patch)
 
-  applyPatch: (patch) ->
+  _applyPatch: (patch) ->
     # In most cases you want applyAndSendPatch.
     # 
-    # This is the only method that writes to the graph!
+    # This is the only method that writes to @graph!
     for quad in patch.delQuads
       @graph.removeTriple(quad)
     for quad in patch.addQuads
@@ -224,6 +246,7 @@
   unsubscribe: (subscription) ->
     @_watchers.unsubscribe(subscription)
 
+
   floatValue: (s, p) ->
     quads = @graph.findByIRI(s, p)
     switch quads.length
@@ -246,24 +269,3 @@
 
   contains: (s, p, o) ->
 
-###
-rdfstore.create((err, store) ->
-  window.store = store
-  store.setPrefix('l9', "http://light9.bigasterisk.com/")
-  store.setPrefix('xsd', "http://www.w3.org/2001/XMLSchema#")
-  store.load('text/turtle', "
-@prefix : <http://light9.bigasterisk.com/> .
-@prefix dev: <http://light9.bigasterisk.com/device/> .
-
-:demoResource :startTime 0.5 .
-    ", (err, n) ->
-      console.log('loaded', n)
-      store.graph (err, graph) ->
-        window.graph = graph
-        
-    )
-  window.URI = (curie) -> store.rdf.createNamedNode(store.rdf.resolve(curie))
-  window.Lit = (value, dtype) -> store.rdf.createLiteral(value, null, URI(dtype))
-
-  )
-###
\ No newline at end of file