Mercurial > code > home > repos > homeauto
comparison lib/patchablegraph.py @ 233:4ebb5cc30002
server/browser graph sync. cut dependency on the WS version. merge some changes between arduino/pi code.
Ignore-this: cf7d20d54e134e8ff33a9ee405610846
author | drewp@bigasterisk.com |
---|---|
date | Sat, 30 Jan 2016 06:40:00 -0800 |
parents | c1b98006f56e |
children | 8d89da1915df |
comparison
equal
deleted
inserted
replaced
232:4e91f3ec460b | 233:4ebb5cc30002 |
---|---|
8 4. The client that got the graph holds and maintains a copy. The | 8 4. The client that got the graph holds and maintains a copy. The |
9 client may merge together multiple graphs. | 9 client may merge together multiple graphs. |
10 5. Client queries its graph with low-level APIs or client-side sparql. | 10 5. Client queries its graph with low-level APIs or client-side sparql. |
11 6. When the graph changes, the client knows and can update itself at | 11 6. When the graph changes, the client knows and can update itself at |
12 low or high granularity. | 12 low or high granularity. |
13 | |
14 | |
15 See also: | |
16 * http://iswc2007.semanticweb.org/papers/533.pdf RDFSync: efficient remote synchronization of RDF | |
17 models | |
18 * https://www.w3.org/2009/12/rdf-ws/papers/ws07 Supporting Change Propagation in RDF | |
19 * https://www.w3.org/DesignIssues/lncs04/Diff.pdf Delta: an ontology for the distribution of | |
20 differences between RDF graphs | |
21 | |
13 """ | 22 """ |
14 import sys, json | 23 import sys, json, logging |
15 import cyclone.sse | 24 import cyclone.sse |
16 sys.path.append("/my/proj/light9") | 25 sys.path.append("/my/proj/light9") |
17 from light9.rdfdb.grapheditapi import GraphEditApi | 26 from light9.rdfdb.grapheditapi import GraphEditApi |
18 from rdflib import ConjunctiveGraph | 27 from rdflib import ConjunctiveGraph |
19 from light9.rdfdb.rdflibpatch import patchQuads | 28 from light9.rdfdb.rdflibpatch import patchQuads |
20 from rdflib_jsonld.serializer import from_rdf | 29 from rdflib_jsonld.serializer import from_rdf |
21 from cycloneerr import PrettyErrorHandler | 30 from cycloneerr import PrettyErrorHandler |
31 | |
32 log = logging.getLogger('patchablegraph') | |
22 | 33 |
23 def writeGraphResponse(req, graph, acceptHeader): | 34 def writeGraphResponse(req, graph, acceptHeader): |
24 if acceptHeader == 'application/nquads': | 35 if acceptHeader == 'application/nquads': |
25 req.set_header('Content-type', 'application/nquads') | 36 req.set_header('Content-type', 'application/nquads') |
26 graph.serialize(req, format='nquads') | 37 graph.serialize(req, format='nquads') |
44 return json.dumps({'patch': { | 55 return json.dumps({'patch': { |
45 'adds': from_rdf(_graphFromQuads2(p.addQuads)), | 56 'adds': from_rdf(_graphFromQuads2(p.addQuads)), |
46 'deletes': from_rdf(_graphFromQuads2(p.delQuads)), | 57 'deletes': from_rdf(_graphFromQuads2(p.delQuads)), |
47 }}) | 58 }}) |
48 | 59 |
60 def graphAsJson(g): | |
61 # This is not the same as g.serialize(format='json-ld')! That | |
62 # version omits literal datatypes. | |
63 return json.dumps(from_rdf(g)) | |
64 | |
49 class PatchableGraph(GraphEditApi): | 65 class PatchableGraph(GraphEditApi): |
50 """ | 66 """ |
51 Master graph that you modify with self.patch, and we get the | 67 Master graph that you modify with self.patch, and we get the |
52 updates to all current listeners. | 68 updates to all current listeners. |
53 """ | 69 """ |
66 addQuads=p.addQuads, | 82 addQuads=p.addQuads, |
67 perfect=False) # true? | 83 perfect=False) # true? |
68 for ob in self._observers: | 84 for ob in self._observers: |
69 ob(patchAsJson(p)) | 85 ob(patchAsJson(p)) |
70 | 86 |
87 def asJsonLd(self): | |
88 return graphAsJson(self._graph) | |
89 | |
71 def addObserver(self, onPatch): | 90 def addObserver(self, onPatch): |
72 self._observers.append(onPatch) | 91 self._observers.append(onPatch) |
73 | 92 |
74 def removeObserver(self, onPatch): | 93 def removeObserver(self, onPatch): |
75 try: | 94 try: |
100 def __init__(self, application, request, masterGraph): | 119 def __init__(self, application, request, masterGraph): |
101 cyclone.sse.SSEHandler.__init__(self, application, request) | 120 cyclone.sse.SSEHandler.__init__(self, application, request) |
102 self.masterGraph = masterGraph | 121 self.masterGraph = masterGraph |
103 | 122 |
104 def bind(self): | 123 def bind(self): |
105 self.sendEvent( | 124 graphJson = self.masterGraph.asJsonLd() |
106 message=self.masterGraph.serialize(None, format='json-ld', | 125 log.debug("send fullGraph event: %s", graphJson) |
107 indent=None), | 126 self.sendEvent(message=graphJson, event='fullGraph') |
108 event='fullGraph') | |
109 self.masterGraph.addObserver(self.onPatch) | 127 self.masterGraph.addObserver(self.onPatch) |
110 | 128 |
111 def onPatch(self, patchJson): | 129 def onPatch(self, patchJson): |
112 # throttle and combine patches here- ideally we could see how | 130 # throttle and combine patches here- ideally we could see how |
113 # long the latency to the client is to make a better rate choice | 131 # long the latency to the client is to make a better rate choice |