# HG changeset patch # User drewp # Date 1580802443 28800 # Node ID c829df2b0dd5cf38d3ff3c50dd0e51cd2e274a7d # Parent 1e9cfec1be784260cef2eef09361de7b130c3aff new graph output for browsers, with autorefresh Ignore-this: e4ff4dbed311b238d90988a1891ef640 darcs-hash:ba19d0d8975104ec6a3580e50cf8b7ca7745abdc diff -r 1e9cfec1be78 -r c829df2b0dd5 lib/patchablegraph/patchablegraph.py --- a/lib/patchablegraph/patchablegraph.py Mon Feb 03 23:46:29 2020 -0800 +++ b/lib/patchablegraph/patchablegraph.py Mon Feb 03 23:47:23 2020 -0800 @@ -20,44 +20,21 @@ differences between RDF graphs """ -import json, logging, itertools +import json, logging, itertools, html from greplin import scales from rdfdb.grapheditapi import GraphEditApi from rdflib import ConjunctiveGraph +from rdflib.namespace import NamespaceManager from rdflib.parser import StringInputSource from rdflib_jsonld.serializer import from_rdf import cyclone.sse - from cycloneerr import PrettyErrorHandler from rdfdb.patch import Patch from rdfdb.rdflibpatch import patchQuads, inGraph log = logging.getLogger('patchablegraph') -def _writeGraphForBrowser(req, graph): - # We think this is a browser, so respond with a live graph view - # (todo) - req.set_header('Content-type', 'text/plain') - lines = graph.serialize(None, format='nquads').splitlines() - lines.sort() - req.write(b'\n'.join(lines)) - - -def _writeGraphResponse(req, graph, acceptHeader: str): - if acceptHeader == 'application/nquads': - req.set_header('Content-type', 'application/nquads') - graph.serialize(req, format='nquads') - elif acceptHeader == 'application/ld+json': - req.set_header('Content-type', 'application/ld+json') - graph.serialize(req, format='json-ld', indent=2) - else: - if acceptHeader.startswith('text/html'): - _writeGraphForBrowser(req, graph) - return - req.set_header('Content-type', 'application/x-trig') - graph.serialize(req, format='trig') - # forked from /my/proj/light9/light9/rdfdb/rdflibpatch.py def _graphFromQuads2(q): g = ConjunctiveGraph() @@ -146,14 +123,91 @@ _sendFullGraph = scales.PmfStat('serve/events/sendFull') _sendPatch = scales.PmfStat('serve/events/sendPatch') + class CycloneGraphHandler(PrettyErrorHandler, cyclone.web.RequestHandler): - def initialize(self, masterGraph): + def initialize(self, masterGraph: PatchableGraph): self.masterGraph = masterGraph def get(self): with self.masterGraph._sendSimpleGraph.time(): - _writeGraphResponse(self, self.masterGraph, - self.request.headers.get('accept', '')) + self._writeGraphResponse() + + def _writeGraphResponse(self): + acceptHeader = self.request.headers.get( + 'Accept', + # see https://github.com/fiorix/cyclone/issues/20 + self.request.headers.get('accept', '')) + + if acceptHeader == 'application/nquads': + self.set_header('Content-type', 'application/nquads') + self.masterGraph.serialize(self, format='nquads') + elif acceptHeader == 'application/ld+json': + self.set_header('Content-type', 'application/ld+json') + self.masterGraph.serialize(self, format='json-ld', indent=2) + else: + if acceptHeader.startswith('text/html'): + self._writeGraphForBrowser() + return + self.set_header('Content-type', 'application/x-trig') + self.masterGraph.serialize(self, format='trig') + + def _writeGraphForBrowser(self): + # We think this is a browser, so respond with a live graph view + # (todo) + self.set_header('Content-type', 'text/html') + + self.write(b''' +
''')
+
+        ns = NamespaceManager(self.masterGraph._graph)
+        # maybe these could be on the PatchableGraph instance
+        ns.bind('ex', 'http://example.com/')
+        ns.bind('', 'http://projects.bigasterisk.com/room/')
+        ns.bind("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
+        ns.bind("xsd", "http://www.w3.org/2001/XMLSchema#")
+
+        for s, p, o, g in sorted(self.masterGraph._graph.quads()):
+            g = g.identifier
+            nquadLine = f'{s.n3(ns)} {p.n3(ns)} {o.n3(ns)} {g.n3(ns)} .\n'
+            self.write(html.escape(nquadLine).encode('utf8'))
+
+        self.write(b'''
+        
+

+ [refresh] + +

+ + + ''') class CycloneGraphEventsHandler(cyclone.sse.SSEHandler): diff -r 1e9cfec1be78 -r c829df2b0dd5 lib/patchablegraph/tasks.py --- a/lib/patchablegraph/tasks.py Mon Feb 03 23:46:29 2020 -0800 +++ b/lib/patchablegraph/tasks.py Mon Feb 03 23:47:23 2020 -0800 @@ -20,5 +20,5 @@ f'--net=host ' f'-v `pwd`:/opt ' f'bang:5000/patchable_graph_browser_test ' - f'/bin/bash' #f'python3 browser_test.py', + f'/bin/bash', #f'python3 browser_test.py', pty=True)