changeset 1350:36f58b2aa8ef

browser syncedgraph sends patches back to server Ignore-this: eb8d3f018ff97f7389c4af3efa62fd9
author Drew Perttula <drewp@bigasterisk.com>
date Sun, 05 Jun 2016 03:21:31 +0000
parents d28e8b76b36f
children 6044e527d795
files bin/rdfdb light9/web/adjustable.coffee light9/web/graph.coffee
diffstat 3 files changed, 65 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/bin/rdfdb	Sun Jun 05 03:04:44 2016 +0000
+++ b/bin/rdfdb	Sun Jun 05 03:21:31 2016 +0000
@@ -417,9 +417,10 @@
             Failure(WebsocketDisconnect(reason)), self.wsClient)
 
     def messageReceived(self, message):
-        log.info("got message from %s: %s", self.connectionId, message)
-        # how
-        self.sendMessage(message)
+        log.info("got message from %r: %s", self.wsClient, message)
+        p = Patch(jsonRepr=message)
+        p.senderUpdateUri = self.wsClient.updateUri
+        self.settings.db.patch(p)
 
 liveClients = set()
 def sendToLiveClients(d=None, asJson=None):
--- a/light9/web/adjustable.coffee	Sun Jun 05 03:04:44 2016 +0000
+++ b/light9/web/adjustable.coffee	Sun Jun 05 03:21:31 2016 +0000
@@ -29,21 +29,18 @@
   subscribe: (onChange) ->
     # change could be displayValue or center or target. This likely
     # calls onChange right away if there's any data yet.
-    setInterval((() => onChange()), 100)
+    throw new Error('not implemented')
 
   startDrag: () ->
-    # todo
-    @dragStartValue = @_getValue()
+    # override
 
   continueDrag: (pos) ->
     # pos is vec2 of pixels relative to the drag start
+
+    # override
     
-    # todo
-    newValue = @dragStartValue + pos.e(0) * .1
-    graph.patchObject(@_subj, @_pred, graph.Literal(newValue), @_ctx)
-
   endDrag: () ->
-    0
+    # override
 
   _editorCoordinates: () -> # vec2 of mouse relative to <l9-t-editor>
     ev = d3.event.sourceEvent
@@ -115,4 +112,6 @@
     # pos is vec2 of pixels relative to the drag start
     
     newValue = @config.getValueForPos(@_editorCoordinates())
-    @config.graph.patchObject(@config.subj, @config.pred, @config.graph.Literal(newValue), @_ctx)
+    @config.graph.patchObject(@config.subj, @config.pred,
+                              @config.graph.LiteralRoundedFloat(newValue),
+                              @config.ctx)
--- a/light9/web/graph.coffee	Sun Jun 05 03:04:44 2016 +0000
+++ b/light9/web/graph.coffee	Sun Jun 05 03:21:31 2016 +0000
@@ -3,6 +3,9 @@
 # Patch is {addQuads: <quads>, delQuads: <quads>}
 # <quads> is [{subject: s, ...}, ...]
 
+patchSizeSummary = (patch) ->
+  '-' + patch.delQuads.length + ' +' + patch.addQuads.length
+
 # partial port of autodepgraphapi.py
 class GraphWatchers
   constructor: ->
@@ -36,6 +39,27 @@
         cb({delQuads: [], addQuads: [quad]})
 
 
+jsonPatch = (jsPatch, cb) ->
+  out = {patch: {adds: '', deletes: ''}}
+
+  writeDels = (cb) ->
+    writer = N3.Writer({ format: 'N-Quads' })
+    writer.addTriples(jsPatch.delQuads)
+    writer.end((err, result) ->
+      out.patch.deletes = result
+      cb())
+
+  writeAdds = (cb) ->
+    writer = N3.Writer({ format: 'N-Quads' })
+    writer.addTriples(jsPatch.addQuads)
+    writer.end((err, result) ->
+      out.patch.adds = result
+      cb())
+    
+  async.parallel([writeDels, writeAdds], (err) ->
+      cb(JSON.stringify(out))
+    )
+
 class window.SyncedGraph
   # Note that applyPatch is the only method to write to the graph, so
   # it can fire subscriptions.
@@ -44,6 +68,7 @@
     @graph = N3.Store()
     @_addPrefixes(prefixes)
     @_watchers = new GraphWatchers()
+    @patchesToSend = []
     @newConnection()
 
   newConnection: ->
@@ -83,6 +108,26 @@
                       cb()
       
     async.parallel([parseAdds, parseDels], ((err) => @applyPatch(patch)))
+
+  _continueSending: ->
+    if @ws.readyState != @ws.OPEN
+      setTimeout(@_continueSending.bind(@), 500)
+      return
+
+    # we could call this less often and coalesce patches together to optimize
+    # the dragging cases.
+
+    sendOne = (patch, cb) =>
+        jsonPatch(patch, (json) =>
+          log('send patch to server, ' + json.length + ' bytes')
+          @ws.send(json)
+          cb(null)
+      )
+
+    async.eachSeries(@patchesToSend, sendOne, () =>
+        @patchesToSend = []
+      )
+    
       
   _addPrefixes: (prefixes) ->
     @graph.addPrefixes(prefixes)
@@ -93,6 +138,10 @@
   Literal: (jsValue) ->
     N3.Util.createLiteral(jsValue)
 
+  LiteralRoundedFloat: (f) ->
+    N3.Util.createLiteral(d3.format(".3f")(f),
+                          "http://www.w3.org/2001/XMLSchema#decimal")
+
   toJs: (literal) ->
     # incomplete
     parseFloat(N3.Util.getLiteralValue(literal))
@@ -113,10 +162,9 @@
 
   applyAndSendPatch: (patch, cb) ->
     @applyPatch(patch)
-    console.log('patch to server:')
-    console.log('  delete:', JSON.stringify(patch.delQuads))
-    console.log('  add:', JSON.stringify(patch.addQuads))
-    # post to server
+    console.log('queue patch to server ', patchSizeSummary(patch))
+    @patchesToSend.push(patch)
+    @_continueSending()
 
   applyPatch: (patch) ->
     # In most cases you want applyAndSendPatch.
@@ -126,7 +174,7 @@
       @graph.removeTriple(quad)
     for quad in patch.addQuads
       @graph.addTriple(quad)
-    log('applied patch -' + patch.delQuads.length + ' +' + patch.addQuads.length)
+    log('applied patch locally', patchSizeSummary(patch))
     @_watchers.graphChanged(patch)
 
   getObjectPatch: (s, p, newObject, g) ->