comparison service/store/store.py @ 411:9fbd2d0193bf

new 'store' service for user inputs Ignore-this: 7b14beca506dd7f1e38b5214aae1833a
author drewp@bigasterisk.com
date Sat, 16 Mar 2019 18:22:57 -0700
parents
children 4c68b604c7ec
comparison
equal deleted inserted replaced
410:a60155ded95f 411:9fbd2d0193bf
1 """
2 persistent store of rdf statements, meant for stmts from users.
3
4 API is not typical rdf: putting statments replaces existing (s,o)
5 matches so there can be only one object at a time. Putting the special
6 object :unset clears the statement.
7 """
8
9 import sys, logging
10 from docopt import docopt
11 from patchablegraph import PatchableGraph, CycloneGraphHandler, CycloneGraphEventsHandler
12 from rdfdb.patch import Patch
13 from rdflib import Namespace, URIRef, Literal, Graph
14 from rdflib.parser import StringInputSource
15 from twisted.internet import reactor
16 from twisted.python.filepath import FilePath
17 import cyclone.web
18
19 ROOM = Namespace('http://projects.bigasterisk.com/room/')
20
21 logging.basicConfig()
22 log = logging.getLogger()
23
24 CTX = ROOM['stored']
25
26 class OutputPage(cyclone.web.RequestHandler):
27 def put(self):
28 arg = self.request.arguments
29 if arg.get('s') and arg.get('p'):
30 self._onQueryStringStatement(arg['s'][-1], arg['p'][-1], self.request.body)
31 else:
32 self._onGraphBodyStatements(self.request.body, self.request.headers)
33
34 def _onQueryStringStatement(self, s, p, body):
35 subj = URIRef(arg['s'][-1])
36 pred = URIRef(arg['p'][-1])
37 turtleLiteral = self.request.body
38 try:
39 obj = Literal(float(turtleLiteral))
40 except ValueError:
41 obj = Literal(turtleLiteral)
42 self._onStatements([(subj, pred, obj)])
43
44 def _onGraphBodyStatements(self, body, headers):
45 # maybe quads only so we can track who made the input and from what interface?
46 # Or your input of triples gets wrapped in a new quad in here?
47 g = Graph()
48 g.parse(StringInputSource(body), format='nt')
49 if not g:
50 raise ValueError("expected graph body")
51 self._onStatements(list(g.triples((None, None, None))))
52
53 def _onStatements(self, stmts):
54 g = self.settings.masterGraph
55 for s, p, o in stmts:
56 patch = g.getObjectPatch(CTX, s, p, o)
57 if o == ROOM['unset']:
58 patch = Patch(delQuads=patch.delQuads)
59 g.patch(patch)
60 nquads = g.serialize(None, format='nquads')
61 self.settings.dbFile.setContent(nquads)
62
63 if __name__ == '__main__':
64 arg = docopt("""
65 Usage: store.py [options]
66
67 -v Verbose
68 """)
69 log.setLevel(logging.WARN)
70 if arg['-v']:
71 from twisted.python import log as twlog
72 twlog.startLogging(sys.stdout)
73 log.setLevel(logging.DEBUG)
74
75 masterGraph = PatchableGraph()
76 dbFile = FilePath('/opt/homeauto_store/db.nquads')
77 if dbFile.exists():
78 masterGraph._graph.parse(dbFile.open(), format='nquads')
79
80 port = 10014
81 reactor.listenTCP(port, cyclone.web.Application([
82 (r"/()", cyclone.web.StaticFileHandler,
83 {"path": ".", "default_filename": "index.html"}),
84 (r"/graph", CycloneGraphHandler, {'masterGraph': masterGraph}),
85 (r"/graph/events", CycloneGraphEventsHandler,
86 {'masterGraph': masterGraph}),
87 (r'/output', OutputPage),
88 ], masterGraph=masterGraph, dbFile=dbFile, debug=arg['-v']),
89 interface='::')
90 log.warn('serving on %s', port)
91
92 reactor.run()