# HG changeset patch # User Drew Perttula # Date 2016-06-05 03:21:31 # Node ID 36f58b2aa8ef0cd3e7b541eae81cb4b776300a2b # Parent d28e8b76b36f241bba59e98e3ea34b9d879727bc browser syncedgraph sends patches back to server Ignore-this: eb8d3f018ff97f7389c4af3efa62fd9 diff --git a/bin/rdfdb b/bin/rdfdb --- a/bin/rdfdb +++ b/bin/rdfdb @@ -417,9 +417,10 @@ class WebsocketClient(cyclone.websocket. 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): diff --git a/light9/web/adjustable.coffee b/light9/web/adjustable.coffee --- a/light9/web/adjustable.coffee +++ b/light9/web/adjustable.coffee @@ -29,21 +29,18 @@ class Adjustable 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 ev = d3.event.sourceEvent @@ -115,4 +112,6 @@ class window.AdjustableFloatObject exten # 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) diff --git a/light9/web/graph.coffee b/light9/web/graph.coffee --- a/light9/web/graph.coffee +++ b/light9/web/graph.coffee @@ -3,6 +3,9 @@ log = console.log # Patch is {addQuads: , delQuads: } # is [{subject: s, ...}, ...] +patchSizeSummary = (patch) -> + '-' + patch.delQuads.length + ' +' + patch.addQuads.length + # partial port of autodepgraphapi.py class GraphWatchers constructor: -> @@ -36,6 +39,27 @@ class GraphWatchers 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 @@ class window.SyncedGraph @graph = N3.Store() @_addPrefixes(prefixes) @_watchers = new GraphWatchers() + @patchesToSend = [] @newConnection() newConnection: -> @@ -83,6 +108,26 @@ class window.SyncedGraph 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 @@ class window.SyncedGraph 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 @@ class window.SyncedGraph 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 @@ class window.SyncedGraph @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) ->