changeset 1491:6cd9341f0a28

xidle rewrite for docker, py3 Ignore-this: a866446f3f42069092dc40b48f12d46b darcs-hash:67026da0e635b31e2cec59037397b99b0ce7c4ac
author drewp <drewp@bigasterisk.com>
date Wed, 29 Jan 2020 01:02:06 -0800
parents 455b1b80516e
children 7c7415cfbc02
files service/xidle/Dockerfile service/xidle/Dockerfile.pi service/xidle/makefile service/xidle/requirements.txt service/xidle/tasks.py service/xidle/xidle.py
diffstat 6 files changed, 129 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/service/xidle/Dockerfile	Thu Jan 23 21:00:47 2020 -0800
+++ b/service/xidle/Dockerfile	Wed Jan 29 01:02:06 2020 -0800
@@ -3,13 +3,12 @@
 RUN apt-get install --yes libxss-dev
 
 COPY requirements.txt ./
-RUN pip install -r requirements.txt
-
-ADD https://projects.bigasterisk.com/rdfdb/more.tgz ./
-RUN tar xvzf more.tgz
+RUN pip3 install --index-url https://projects.bigasterisk.com/ --extra-index-url https://pypi.org/simple -r requirements.txt
+# not sure why this doesn't work from inside requirements.txt
+RUN pip3 install -U 'https://github.com/drewp/cyclone/archive/python3.zip?v3'
 
 COPY *.py ./
 
 EXPOSE 9107
 
-CMD [ "python", "./xidle.py" ]
+CMD [ "python3", "./xidle.py" ]
--- a/service/xidle/Dockerfile.pi	Thu Jan 23 21:00:47 2020 -0800
+++ b/service/xidle/Dockerfile.pi	Wed Jan 29 01:02:06 2020 -0800
@@ -3,13 +3,12 @@
 RUN apt-get install --yes libxss-dev
 
 COPY requirements.txt ./
-RUN pip install -r requirements.txt
-
-ADD https://projects.bigasterisk.com/rdfdb/more.tgz ./
-RUN tar xvzf more.tgz
+RUN pip3 install --index-url https://projects.bigasterisk.com/ --extra-index-url https://pypi.org/simple -r requirements.txt
+# not sure why this doesn't work from inside requirements.txt
+RUN pip3 install -U 'https://github.com/drewp/cyclone/archive/python3.zip?v3'
 
 COPY *.py ./
 
 EXPOSE 9107
 
-CMD [ "python", "./xidle.py" ]
+CMD [ "python3", "./xidle.py" ]
--- a/service/xidle/makefile	Thu Jan 23 21:00:47 2020 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-build_image:
-	(cd /my/proj/homeauto/lib; tar czf /my/site/projects/rdfdb/more.tgz *.py)
-	docker build --network=host -t bang6:5000/xidle_x86:latest .
-	docker push bang6:5000/xidle_x86:latest
-
-build_image_pi:
-	(cd /my/proj/homeauto/lib; tar czf /my/site/projects/rdfdb/more.tgz *.py)
-	docker build --file Dockerfile.pi --network=host -t bang6:5000/xidle_pi:latest .
-	docker push bang6:5000/xidle_pi:latest
-
-shell:
-	docker run --rm -it --cap-add SYS_PTRACE -v /tmp/.X11-unix/:/tmp/.X11-unix/ -v /home/drewp/.Xauthority:/root/.Xauthority --net=host bang6:5000/xidle_x86:latest  /bin/sh
-
-local_run:
-	docker run --rm -it -v /tmp/.X11-unix/:/tmp/.X11-unix/ -v /home/drewp/.Xauthority:/root/.Xauthority -p 9107:9107 --net=host bang6:5000/xidle_x86:latest python ./xidle.py -v
-
-redeploy: build_image build_image_pi
-	sudo /my/proj/ansible/playbook -t homeauto_xidle
--- a/service/xidle/requirements.txt	Thu Jan 23 21:00:47 2020 -0800
+++ b/service/xidle/requirements.txt	Wed Jan 29 01:02:06 2020 -0800
@@ -1,9 +1,11 @@
-python-dateutil
-rdflib==4.2.2
-
+cyclone
 influxdb==4.1.1
-cyclone
+python-dateutil
+rdflib-jsonld==0.3
+rdflib==4.2.2
 service_identity
-actmon
-https://projects.bigasterisk.com/rdfdb/rdfdb-0.3.0.tar.gz
-rdflib-jsonld==0.3
+
+git+http://github.com/drewp/scales.git@448d59fb491b7631877528e7695a93553bfaaa93#egg=scales
+patchablegraph==0.7.0
+rdfdb==0.9.0
+standardservice==0.6.0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/xidle/tasks.py	Wed Jan 29 01:02:06 2020 -0800
@@ -0,0 +1,33 @@
+from invoke import task
+JOB = 'xidle'
+PORT = 9107
+TAG_x86 = f'bang6:5000/{JOB.lower()}_x86:latest'
+TAG_pi = f'bang6:5000/{JOB.lower()}_pi:latest'
+ANSIBLE_TAG = 'homeauto_xidle'
+
+@task
+def build_image_x86(ctx):
+    ctx.run(f'docker build --network=host -t {TAG_x86} .')
+@task
+def build_image_pi(ctx):
+    ctx.run(f'docker build --file Dockerfile.pi --network=host -t {TAG_pi} .')
+
+@task(pre=[build_image_x86])
+def push_image_x86(ctx):
+    ctx.run(f'docker push {TAG_x86}')
+@task(pre=[build_image_pi])
+def push_image_pi(ctx):
+    ctx.run(f'docker push {TAG_pi}')
+
+@task(pre=[build_image_x86])
+def shell(ctx):
+    ctx.run(f'docker run --rm -it --cap-add SYS_PTRACE -v /tmp/.X11-unix/:/tmp/.X11-unix/ -v /home/drewp/.Xauthority:/root/.Xauthority --net=host {TAG_x86} /bin/bash', pty=True)
+
+@task(pre=[build_image_x86])
+def local_run(ctx):
+    ctx.run(f'docker run --rm -it -v /tmp/.X11-unix/:/tmp/.X11-unix/ -v /home/drewp/.Xauthority:/root/.Xauthority -p {PORT}:{PORT} -v /etc/resolv.conf:/etc/resolv.conf --net=host {TAG_x86} python3 xidle.py -v', pty=True)
+
+@task(pre=[push_image_x86, push_image_pi])
+def redeploy(ctx):
+    ctx.run(f'sudo /my/proj/ansible/playbook -t {ANSIBLE_TAG}')
+    #ctx.run(f'supervisorctl -s http://bang:9001/ restart {JOB}_{PORT}')
--- a/service/xidle/xidle.py	Thu Jan 23 21:00:47 2020 -0800
+++ b/service/xidle/xidle.py	Wed Jan 29 01:02:06 2020 -0800
@@ -1,5 +1,3 @@
-#!bin/python
-from __future__ import division
 """
 X server idle time is now available over http!
 
@@ -8,60 +6,112 @@
 
     xinput disable "HP Webcam HD-4110"
 """
-
 import time
-import sys, socket, json, os
+import socket, json, os
 from rdflib import Namespace, URIRef, Literal
 from influxdb import InfluxDBClient
 import influxdb.exceptions
 import cyclone.web
 from twisted.internet import reactor, task
-
-import actmon
-# another option: http://thp.io/2007/09/x11-idle-time-and-focused-window-in.html
+from standardservice.logsetup import log, verboseLogging
+from patchablegraph import PatchableGraph, CycloneGraphEventsHandler, CycloneGraphHandler
 
 DEV = Namespace("http://projects.bigasterisk.com/device/")
 ROOM = Namespace("http://projects.bigasterisk.com/room/")
 
-sys.path.append('../../lib')
-from patchablegraph import PatchableGraph, CycloneGraphEventsHandler, CycloneGraphHandler
-
 host = socket.gethostname()
 client = InfluxDBClient('bang6', 9060, 'root', 'root', 'main')
 
 os.environ['DISPLAY'] = ':0.0'
 
-actmon.get_idle_time() # fail if we can't get the display or something
+import pxss
+# another option: http://thp.io/2007/09/x11-idle-time-and-focused-window-in.html
+
+def get_idle_time():
+    return pxss.get_info().idle
+
+get_idle_time() # fail if we can't get the display or something
 
 class Root(cyclone.web.RequestHandler):
     def get(self):
-        actmon.get_idle_time() # fail if we can't get the display or something
+        get_idle_time() # fail if we can't get the display or something
+        self.set_header('content-type', 'text/html')
         self.write('''
+        <!doctype html>
+<html>
+  <head>
+    <title>xidle</title>
+    <meta charset="utf-8" />
+    <script src="/lib/polymer/1.0.9/webcomponentsjs/webcomponents.min.js"></script>
+    <script src="/lib/require/require-2.3.3.js"></script>
+    <script src="/rdf/common_paths_and_ns.js"></script>
+
+    <link rel="import" href="/rdf/streamed-graph.html">
+    <link rel="import" href="/lib/polymer/1.0.9/polymer/polymer.html">
+
+    <meta name="mobile-web-app-capable" content="yes">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+  </head>
+  <body>
+    <template id="t" is="dom-bind">
+
       Get the <a href="idle">X idle time</a> on %s.
-      <a href="graph">rdf graph</a> available.''' % host)
-        
+
+      <streamed-graph url="graph/xidle/events" graph="{{graph}}"></streamed-graph>
+      <div id="out"></div>
+      <script type="module" src="/rdf/streamed_graph_view.js"></script>
+    </template>
+    <style>
+     .served-resources {
+         margin-top: 4em;
+         border-top: 1px solid gray;
+         padding-top: 1em;
+     }
+     .served-resources a {
+         padding-right: 2em;
+     }
+    </style>
+
+      <div class="served-resources">
+        <a href="stats/">/stats/</a>
+        <a href="graph/dpms">/graph/dpms</a>
+        <a href="graph/dpms/events">/graph/dpms/events</a>
+        <a href="idle">/idle</a>
+    </div>
+
+  </body>
+</html>
+        ''' % host)
+
 class Idle(cyclone.web.RequestHandler):
     def get(self):
         self.set_header('Content-type', 'application/json')
-        self.write(json.dumps({"idleMs" : actmon.get_idle_time()}))
-        
+        self.write(json.dumps({"idleMs" : get_idle_time()}))
+
 class Poller(object):
     def __init__(self):
         self.points = []
         self.lastSent = None
         self.lastSentTime = 0
-        task.LoopingCall(self.poll).start(5)
-        
+        self.lastGraphSent = None
+        self.lastGraphSentTime = 0
+        task.LoopingCall(self.poll).start(1)
+
     def poll(self):
-        ms = actmon.get_idle_time()
+        ms = get_idle_time()
         ctx = DEV['xidle/%s' % host]
         subj = URIRef("http://bigasterisk.com/host/%s/xidle" % host)
-        masterGraph.patchObject(ctx, subj, ROOM['idleTimeMs'], Literal(ms))
-        masterGraph.patchObject(ctx, subj, ROOM['idleTimeMinutes'],
-                                Literal(ms / 1000 / 60))
-        
         lastMinActive = ms < 60 * 1000
         now = int(time.time())
+
+        nextGraphUpdate = self.lastGraphSentTime + min(10, ms / 1000 / 2)
+        if self.lastGraphSent != lastMinActive or now > nextGraphUpdate:
+            masterGraph.patchObject(ctx, subj, ROOM['idleTimeMs'], Literal(ms))
+            masterGraph.patchObject(ctx, subj, ROOM['idleTimeMinutes'],
+                                    Literal(round(ms / 1000 / 60, 2)))
+            self.lastGraphSent = lastMinActive
+            self.lastGraphSentTime = now
+
         if self.lastSent != lastMinActive or now > self.lastSentTime + 3600:
             self.points.append({"measurement": "presence",
                                 "tags": {"host": host, "sensor": "xidle"},
@@ -73,19 +123,20 @@
             try:
                 client.write_points(self.points, time_precision='s')
             except influxdb.exceptions.InfluxDBServerError as e:
-                print repr(e)
+                log.error(repr(e))
                 reactor.crash()
             self.points = []
 
-            
+verboseLogging(False)
+
 masterGraph = PatchableGraph()
 poller = Poller()
-            
+
 reactor.listenTCP(9107, cyclone.web.Application([
     (r'/', Root),
     (r'/idle', Idle),
-    (r'/graph', CycloneGraphHandler, {'masterGraph': masterGraph}),
-    (r'/graph/events', CycloneGraphEventsHandler, {'masterGraph': masterGraph}),
+    (r'/graph/xidle', CycloneGraphHandler, {'masterGraph': masterGraph}),
+    (r'/graph/xidle/events', CycloneGraphEventsHandler, {'masterGraph': masterGraph}),
 ]), interface='::')
 
 reactor.run()