Changeset - 30c79f1dc4f8
[Not reviewed]
default
0 5 0
Drew Perttula - 8 years ago 2017-05-30 07:36:42
drewp@bigasterisk.com
fix suggestPrefixes to send suggestions to rdfdb
Ignore-this: 637142dcc1de97c9046d75d1396a9446
5 files changed with 58 insertions and 32 deletions:
0 comments (0 inline, 0 general)
bin/effecteval
Show inline comments
 
@@ -69,13 +69,13 @@ class SongEffects(PrettyErrorHandler, cy
 
            note = URIRef(note)
 

	
 
        log.info("adding to %s", song)
 
        note, p = yield songNotePatch(self.settings.graph, dropped, song, event, ctx=song, note=note)
 
        
 
        self.settings.graph.patch(p)
 
        self.settings.graph.suggestPrefixes({'song': URIRef(song + '/')})
 
        self.settings.graph.suggestPrefixes(song, {'song': URIRef(song + '/')})
 
        self.write(json.dumps({'note': note}))
 
        
 
class SongEffectsUpdates(cyclone.websocket.WebSocketHandler):
 
    def connectionMade(self, *args, **kwargs):
 
        self.graph = self.settings.graph
 
        self.graph.addHandler(self.updateClient)
bin/rdfdb
Show inline comments
 
@@ -177,13 +177,13 @@ class WsClient(object):
 
class WatchedFiles(object):
 
    """
 
    find files, notice new files.
 

	
 
    This object watches directories. Each GraphFile watches its own file.
 
    """
 
    def __init__(self, dirUriMap, patch, getSubgraph, addlPrefixes=None):
 
    def __init__(self, dirUriMap, patch, getSubgraph, addlPrefixes):
 
        self.dirUriMap = dirUriMap # {abspath : uri prefix}
 
        self.patch, self.getSubgraph = patch, getSubgraph
 
        self.addlPrefixes = addlPrefixes
 
        
 
        self.graphFiles = {} # context uri : GraphFile
 
        
 
@@ -236,16 +236,13 @@ class WatchedFiles(object):
 
        # read into one file called config.n3. New versions won't read
 
        # it.
 
        if inFile.endswith("config.n3"):
 
            return
 
            
 
        ctx = uriFromFile(self.dirUriMap, inFile)
 
        gf = GraphFile(self.notifier, inFile, ctx,
 
                       self.patch, self.getSubgraph,
 
                       addlPrefixes=self.addlPrefixes)
 
        self.graphFiles[ctx] = gf
 
        gf = self._addGraphFile(ctx, inFile)
 
        log.info("%s do initial read", inFile)
 
        gf.reread()
 

	
 
    def aboutToPatch(self, ctx):
 
        """
 
        warn us that a patch is about to come to this context. it's more
 
@@ -260,16 +257,25 @@ class WatchedFiles(object):
 
        g = self.getSubgraph(ctx)
 

	
 
        if ctx not in self.graphFiles:
 
            outFile = fileForUri(self.dirUriMap, ctx)
 
            assert '//' not in outFile, (outFile, self.dirUriMap, ctx)
 
            log.info("starting new file %r", outFile)
 
            self.graphFiles[ctx] = GraphFile(self.notifier, outFile, ctx,
 
                                             self.patch, self.getSubgraph,
 
                                             addlPrefixes=self.addlPrefixes)
 
            self._addGraphFile(ctx, outFile)
 

	
 
    def _addGraphFile(self, ctx, path):
 
        self.addlPrefixes.setdefault(ctx, {})
 
        self.addlPrefixes.setdefault(None, {})
 
        gf = GraphFile(self.notifier, path, ctx,
 
                       self.patch, self.getSubgraph,
 
                       globalPrefixes=self.addlPrefixes[None],
 
                       ctxPrefixes=self.addlPrefixes[ctx])
 
        self.graphFiles[ctx] = gf 
 
        return gf
 

	
 
            
 
    def dirtyFiles(self, ctxs):
 
        """mark dirty the files that we watch in these contexts.
 

	
 
        the ctx might not be a file that we already read; it might be
 
        for a new file we have to create, or it might be for a
 
        transient context that we're not going to save
 
@@ -282,19 +288,20 @@ class WatchedFiles(object):
 

	
 
        
 
class Db(object):
 
    """
 
    the master graph, all the connected clients, all the files we're watching
 
    """
 
    def __init__(self, dirUriMap, addlPrefixes=None):
 
    def __init__(self, dirUriMap, addlPrefixes):
 
      
 
        self.clients = []
 
        self.graph = ConjunctiveGraph()
 

	
 
        self.watchedFiles = WatchedFiles(dirUriMap,
 
                                         self.patch, self.getSubgraph, addlPrefixes)
 
                                         self.patch, self.getSubgraph,
 
                                         addlPrefixes)
 
        
 
        self.summarizeToLog()
 

	
 
    def patch(self, p, dueToFileChange=False):
 
        """
 
        apply this patch to the master graph then notify everyone about it
 
@@ -400,12 +407,18 @@ class GraphClients(PrettyErrorHandler, c
 
            self.settings.db.addClient(Client(upd, self.get_argument("label")))
 
        except:
 
            import traceback
 
            traceback.print_exc()
 
            raise
 
            
 
class Prefixes(PrettyErrorHandler, cyclone.web.RequestHandler):
 
    def post(self):
 
        suggestion = json.loads(self.request.body)
 
        addlPrefixes = self.settings.db.watchedFiles.addlPrefixes
 
        addlPrefixes.setdefault(URIRef(suggestion['ctx']), {}).update(suggestion['prefixes'])
 
    
 
_wsClientSerial = 0
 
class WebsocketClient(cyclone.websocket.WebSocketHandler):
 

	
 
    def connectionMade(self, *args, **kwargs):
 
        global _wsClientSerial
 
        connectionId = 'connection-%s' % _wsClientSerial
 
@@ -454,12 +467,14 @@ class NoExts(cyclone.web.StaticFileHandl
 
    # .html pages can be get() without .html on them
 
    def get(self, path, *args, **kw):
 
        if path and '.' not in path:
 
            path = path + ".html"
 
        cyclone.web.StaticFileHandler.get(self, path, *args, **kw)
 

	
 

	
 
        
 
if __name__ == "__main__":
 
    logging.basicConfig()
 
    log = logging.getLogger()
 

	
 
    parser = optparse.OptionParser()
 
    parser.add_option("-v", "--verbose", action="store_true",
 
@@ -467,23 +482,32 @@ if __name__ == "__main__":
 
    (options, args) = parser.parse_args()
 

	
 
    log.setLevel(logging.DEBUG if options.verbose else logging.INFO)
 

	
 
    db = Db(dirUriMap={os.environ['LIGHT9_SHOW'].rstrip('/') + '/':
 
                       showconfig.showUri() + '/'},
 
            addlPrefixes={'show': URIRef(showconfig.showUri() + '/')})
 
            addlPrefixes={None: {
 
                'show': showconfig.showUri() + '/',
 
                '': 'http://light9.bigasterisk.com/',
 
                'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
 
                'rdfs': 'http://www.w3.org/2000/01/rdf-schema#',
 
                'xsd': 'http://www.w3.org/2001/XMLSchema#',
 
                'effect': 'http://light9.bigasterisk.com/effect/',
 
                'dev': 'http://light9.bigasterisk.com/device/',
 
            }})
 

	
 
    from twisted.python import log as twlog
 
    twlog.startLogging(sys.stdout)
 

	
 
    reactor.listenTCP(networking.rdfdb.port, cyclone.web.Application(handlers=[
 
        (r'/live', Live),
 
        (r'/graph', GraphResource),
 
        (r'/patches', Patches),
 
        (r'/graphClients', GraphClients),
 
        (r'/syncedGraph', WebsocketClient),
 
        (r'/prefixes', Prefixes),
 

	
 
        (r'/(.*)', NoExts,
 
         {"path" : "light9/rdfdb/web",
 
          "default_filename" : "index.html"}),
 

	
 
        ], debug=True, db=db))
light9/paint/capture.py
Show inline comments
 
@@ -12,13 +12,14 @@ def writeCaptureDescription(graph, ctx, 
 
        settingsSubgraphCache=settingsSubgraphCache)))
 
    graph.patch(Patch(addQuads=[
 
        (dev, L9['capture'], uri, ctx),
 
        (uri, RDF.type, L9['LightSample'], ctx),
 
        (uri, L9['imagePath'], URIRef('/'.join([showconfig.showUri(), relOutPath])), ctx),
 
        ]))
 
    graph.suggestPrefixes('cap', URIRef(uri.rsplit('/', 1)[0] + '/'))
 
    graph.suggestPrefixes(ctx, {'cap': uri.rsplit('/', 1)[0] + '/',
 
                                'showcap': showconfig.showUri() + '/capture/'})
 
    
 
class CaptureLoader(object):
 
    def __init__(self, graph):
 
        self.graph = graph
 
        
 
    def loadImage(self, pic, thumb=(100, 100)):
light9/rdfdb/graphfile.py
Show inline comments
 
@@ -6,13 +6,13 @@ from rdflib import Graph, RDF
 
from light9.rdfdb.patch import Patch
 
from light9.rdfdb.rdflibpatch import inContext
 

	
 
log = logging.getLogger('graphfile')
 
iolog = logging.getLogger('io')
 

	
 
def patchN3SerializerToUseLessWhitespace():
 
def patchN3SerializerToUseLessWhitespace(cutColumn=65):
 
    # todo: make a n3serializer subclass with whitespace settings
 
    from rdflib.plugins.serializers.turtle import TurtleSerializer, OBJECT
 
    originalWrite = TurtleSerializer.write
 
    def write(self, s):
 
        lines = s.split('\n')
 
        if len(lines) > 1:
 
@@ -28,13 +28,13 @@ def patchN3SerializerToUseLessWhitespace
 
            return
 
        self.verb(propList[0], newline=newline)
 
        self.objectList(properties[propList[0]])
 
        for predicate in propList[1:]:
 
            self.write(';')
 
            # can't do proper wrapping since we don't know how much is coming
 
            if self._column > 50:
 
            if self._column > cutColumn:
 
                self.write('\n' + self.indent(1))
 
            self.verb(predicate, newline=False)
 
            self.objectList(properties[predicate])
 
    def objectList(self, objects):
 
        count = len(objects)
 
        if count == 0:
 
@@ -60,35 +60,30 @@ def patchN3SerializerToUseLessWhitespace
 
patchN3SerializerToUseLessWhitespace()
 

	
 
class GraphFile(object):
 
    """
 
    one rdf file that we read from, write to, and notice external changes to
 
    """
 
    def __init__(self, notifier, path, uri, patch, getSubgraph, addlPrefixes=None):
 
    def __init__(self, notifier, path, uri, patch, getSubgraph, globalPrefixes, ctxPrefixes):
 
        """
 
        uri is the context for the triples in this file. We assume
 
        sometimes that we're the only ones with triples in this
 
        context.
 
        
 
        this does not include an initial reread() call
 

	
 
        Prefixes are mutable dicts. The caller may add to them later.
 
        """
 
        self.path, self.uri = path, uri
 
        self.patch, self.getSubgraph = patch, getSubgraph
 

	
 
        self.lastWriteTimestamp = 0 # mtime from the last time _we_ wrote
 

	
 
        self.namespaces = {
 
            '': 'http://light9.bigasterisk.com/',
 
            'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
 
            'rdfs': 'http://www.w3.org/2000/01/rdf-schema#',
 
            'xsd': 'http://www.w3.org/2001/XMLSchema#',
 
            'effect': 'http://light9.bigasterisk.com/effect/',
 
            'dev': 'http://light9.bigasterisk.com/device/',
 
        }
 
        if addlPrefixes:
 
            self.namespaces.update(addlPrefixes)
 
        self.globalPrefixes = globalPrefixes
 
        self.ctxPrefixes = ctxPrefixes
 
        self.readPrefixes = {}
 
        
 
        if not os.path.exists(path):
 
            # can't start notify until file exists
 
            try:
 
                os.makedirs(os.path.dirname(path))
 
            except OSError:
 
@@ -184,13 +179,13 @@ class GraphFile(object):
 
                # patch our graph as if it had just been cleared. We
 
                # shouldn't even be here reading this, but
 
                # lastWriteTimestamp didn't work.
 
                return
 

	
 
            new.parse(location=self.path, format='n3')
 
            self.namespaces.update(dict(new.namespaces()))
 
            self.readPrefixes = dict(new.namespaces())
 
        except SyntaxError as e:
 
            print e
 
            traceback.print_exc()
 
            log.error("%s syntax error", self.path)
 
            # todo: likely bug- if a file has this error upon first
 
            # read, I think we don't retry it right.
 
@@ -236,13 +231,15 @@ class GraphFile(object):
 
    def flush(self):
 
        self.writeCall = None
 

	
 
        tmpOut = self.path + ".rdfdb-temp"
 
        f = open(tmpOut, 'w')
 
        t1 = time.time()
 
        for p, n in self.namespaces.items():
 
        for p, n in (self.globalPrefixes.items() +
 
                     self.readPrefixes.items() +
 
                     self.ctxPrefixes.items()):
 
            self.graphToWrite.bind(p, n)
 
        self.graphToWrite.serialize(destination=f, format='n3')
 
        serializeTime = time.time() - t1
 
        f.close()
 
        self.lastWriteTimestamp = os.path.getmtime(tmpOut)
 
        os.rename(tmpOut, self.path)
light9/rdfdb/syncedgraph.py
Show inline comments
 
@@ -16,12 +16,13 @@ PatchReceiver - our web server that list
 
PatchSender - collects and transmits your graph edits
 
"""
 

	
 
from rdflib import ConjunctiveGraph
 
import logging, cyclone.httpclient, traceback
 
from twisted.internet import defer
 
import treq, json
 
log = logging.getLogger('syncedgraph')
 
from light9.rdfdb.rdflibpatch import patchQuads
 

	
 
from light9.rdfdb.patchsender import PatchSender
 
from light9.rdfdb.patchreceiver import PatchReceiver
 
from light9.rdfdb.currentstategraphapi import CurrentStateGraphApi
 
@@ -122,16 +123,19 @@ class SyncedGraph(CurrentStateGraphApi, 
 
        log.debug('runDepsOnNewPatch')
 
        self.runDepsOnNewPatch(p)
 
        log.debug('sendPatch')
 
        self._sender.sendPatch(p).addErrback(self.sendFailed)
 
        log.debug('patch is done %s', debugKey)
 

	
 
    def suggestPrefixes(self, prefixes):
 
        if not hasattr(self, 'addlPrefixes'):
 
            self.addlPrefixes = {}
 
        self.addlPrefixes.update(prefixes)
 
    def suggestPrefixes(self, ctx, prefixes):
 
        """
 
        when writing files for this ctx, try to use these n3
 
        prefixes. async, not guaranteed to finish before any
 
        particular file flush
 
        """
 
        treq.post(self.rdfdbRoot + 'prefixes', json.dumps({'ctx': ctx, 'prefixes': prefixes}))
 

	
 
    def sendFailed(self, result):
 
        """
 
        we asked for a patch to be queued and sent to the master, and
 
        that ultimately failed because of a conflict
 
        """
0 comments (0 inline, 0 general)