diff service/reasoning/reasoning.py @ 934:3bb18b7d21df

reasoning actions: generalize them a bit but then add a bunch of special cases for mpd for now Ignore-this: 3ab80fee5836817dcd54ce6678a6089d darcs-hash:20131009044224-312f9-b47b461e8872e4ef5c4951703ab8f13d5b848ea3
author drewp <drewp@bigasterisk.com>
date Tue, 08 Oct 2013 21:42:24 -0700
parents 4ae49c6adecb
children 0f2ac014d9ea
line wrap: on
line diff
--- a/service/reasoning/reasoning.py	Tue Oct 08 21:39:06 2013 -0700
+++ b/service/reasoning/reasoning.py	Tue Oct 08 21:42:24 2013 -0700
@@ -19,7 +19,7 @@
 from twisted.internet import reactor, task
 from twisted.web.client import getPage
 from twisted.python.filepath import FilePath
-import time, traceback, sys, json, logging
+import time, traceback, sys, json, logging, urllib
 from rdflib.Graph import Graph, ConjunctiveGraph
 from rdflib import Namespace, URIRef, Literal, RDF, StringInputSource
 from FuXi.Rete.RuleStore import N3RuleStore
@@ -244,8 +244,8 @@
 
     def _put(self, url, payload):
         def err(e):
-            outlog.warn("put %s failed", url)
-        outlog.info("PUT %s payload=%r", url, payload)
+            outlog.warn("    put %s failed", url)
+        outlog.info("    PUT %s payload=%r", url, payload)
         fetch(url, method="PUT", postdata=payload, timeout=2).addErrback(err)
 
     def putResults(self, inferred):
@@ -290,29 +290,66 @@
 
 
     def oneShotPostActions(self, deviceGraph, inferred):
+        """
+        Inferred graph may contain some one-shot statements. We'll send
+        statement objects to anyone on web sockets, and also generate
+        POST requests as described in the graph.
+
+        one-shot statement ?s ?p ?o
+        with this in the graph:
+          ?osp a :OneShotPost
+          ?osp :subject ?s
+          ?osp :predicate ?p
+        this will cause a post to ?o 
+        """
         # nothing in this actually makes them one-shot yet. they'll
         # just fire as often as we get in here, which is not desirable
-        for s, p in [
-                (URIRef('http://bigasterisk.com/host/star/slideshow'), ROOM.postAction),
-                (URIRef('http://bigasterisk.com/host/star/sound'), ROOM.postAction),
-                (URIRef('http://bigasterisk.com/host/slash/sound'), ROOM.postAction),
-            ]:
-            log.info("find inferred objs %r %r" % (s, p))
+        log.info("oneShotPostActions")
+        def err(e):
+            outlog.warn("post %s failed", postTarget)
+        for osp in deviceGraph.subjects(RDF.type, ROOM['OneShotPost']):
+            s = deviceGraph.value(osp, ROOM['subject'])
+            p = deviceGraph.value(osp, ROOM['predicate'])
+            if s is None or p is None:
+                continue
             for postTarget in inferred.objects(s, p):
                 log.info("post target %r", postTarget)
+                # this packet ought to have 'oneShot' in it somewhere
                 sendToLiveClients({"s":s, "p":p, "o":postTarget})
-                if s in [URIRef('http://bigasterisk.com/host/star/sound'),
-                         URIRef('http://bigasterisk.com/host/slash/sound'),
-                         URIRef('http://bigasterisk.com/host/star/slideshow'),
-                        ]:
-                    try:
-                        response = restkit.request(url=postTarget, method="POST", body="")
-                    except Exception, e:
-                        log.warn("post to %s failed: %s" % (postTarget, e))
-                    else:
-                        log.info("post to %s got status %s" %
-                                 (postTarget, response.status))
 
+                outlog.info("    POST %s", postTarget)
+                fetch(postTarget, method="POST", timeout=2).addErrback(err)
+        self.postMpdCommands(inferred)
+        
+    def postMpdCommands(self, inferred):
+        """special case to be eliminated. mpd play urls are made of an
+        mpd service and a song/album/playlist uri to be played.
+        Ideally the graph rules would assemble these like
+        http://{mpd}/addAndPlay?uri={toPlay} or maybe toPlay as the payload
+        which would be fairly general but still allow toPlay uris to
+        be matched with any player."""
+        def post(postTarget):
+            outlog.info("special mpd POST %s", postTarget)
+            def err(e):
+                outlog.warn("post %s failed", postTarget)
+            fetch(postTarget, method="POST", timeout=2).addErrback(err)
+        root = "http://bigasterisk.com/music/slash/mpd/"
+        rootSkippingAuth = "http://slash:9009/"
+        slashMpd = URIRef("http://bigasterisk.com/host/slash/mpd")
+        for song in inferred.objects(slashMpd, ROOM['startMusic']):
+            outlog.info("mpd statement: %r" % song)
+            assert song.startswith('http://bigasterisk.com/music/')
+            post(rootSkippingAuth + "addAndPlay" + urllib.quote(song[len("http://bigasterisk.com/music"):]))
+            
+        for state in inferred.objects(slashMpd, ROOM['playState']):
+            if state == ROOM['pause']:
+                post(rootSkippingAuth + "mpd/pause")
+        for vol in inferred.objects(slashMpd, ROOM['audioState']):
+            if vol == ROOM['volumeStepUp']:
+                post(rootSkippingAuth + "volumeAdjust?amount=6&max=70")
+            if vol == ROOM['volumeStepDown']:
+                post(rootSkippingAuth + "volumeAdjust?amount=-6&min=10")
+            
     def putZero(self, deviceGraph, dev, pred, putUrl):
         # zerovalue should be a function of pred as well.
         value = deviceGraph.value(dev, ROOM.zeroValue)
@@ -399,6 +436,9 @@
         everything appears to be a 'change'.
         """
         g = parseRdf(self.request.body, self.request.headers['content-type'])
+        if not len(g):
+            log.warn("incoming oneshot graph had no statements: %r", self.request.body)
+            return
         self.settings.reasoning.inputGraph.addOneShot(g)
 
 # for reuse