Share the code for on-demand resources
authorEnrico Zini <enrico@enricozini.org>
Mon, 15 Jun 2009 14:36:40 +0000 (22:36 +0800)
committerEnrico Zini <enrico@enricozini.org>
Mon, 15 Jun 2009 14:36:40 +0000 (22:36 +0800)
zavai/__init__.py
zavai/app.py
zavai/gps.py
zavai/registry.py

index a510b5229b8b47e2d372bc8a53e951eed0957873..a13a0b594df667b5c33907675e55560721818e47 100644 (file)
@@ -19,7 +19,7 @@
 from conf import read_config
 from config import Config
 from plugins import load_plugins
-from registry import Registry, Resource, get_parent, default_label
+from registry import Registry, Resource, Service, get_parent, default_label
 from menu import Menu, MenuButton, LinkButton, ToggleButton
 from app import Zavai, Applet
 from gps import GPS, GPX
@@ -34,3 +34,4 @@ def info(*args):
 def set_quiet():
     def info(*args):
         pass
+
index 2d8020e245f041eab9d466ea2264e105c0590fb8..4ce7852dca06fe88d60779837ec4767251803357 100644 (file)
@@ -55,6 +55,7 @@ class Zavai(gtk.Window, zavai.Resource):
         widget.show_all()
 
     def run(self):
+        self.set_size_request(100, 200)
         #self.fullscreen()
         self.show_all()
         gtk.main()
index fb483aff56429cefdc2d504ad012c10fe4e1e91a..f0d11f244f81d0f34235be16363b1c1499829612 100755 (executable)
@@ -23,8 +23,10 @@ import time
 import dbus
 import zavai
 
-class GPSMonitor():
+class GPSMonitor(zavai.Service):
     def __init__(self, gps):
+        super(GPSMonitor, self).__init__()
+
         self.gps = gps
         self.gps_ubx = gps.gps_ubx
 
@@ -34,8 +36,6 @@ class GPSMonitor():
         self.debug_have = set()
         self.debug_error = set()
 
-        self.callbacks = set()
-
     def debug_update(self):
         if self.debug_busy is None:
             pending = self.debug_want - self.debug_have - self.debug_error
@@ -69,10 +69,9 @@ class GPSMonitor():
 
     def on_ubxdebug_packet(self, clid, length, data):
         zavai.info("gps monitor: UBX debug packet")
-        for c in self.callbacks:
-            c(clid, length, data)
+        self.notify(clid, length, data)
 
-    def _start_listening(self):
+    def start(self):
         self.gps.request(self)
         # TODO: find out how come sometimes these events are not sent
         self.gps.bus.add_signal_receiver(
@@ -83,7 +82,7 @@ class GPSMonitor():
             'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
         self.debug_request()
 
-    def _stop_listening(self):
+    def stop(self):
         self.gps.bus.remove_signal_receiver(
             self.on_satellites_changed, 'SatellitesChanged', 'org.freedesktop.Gypsy.Satellite',
             'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
@@ -92,60 +91,32 @@ class GPSMonitor():
             'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
         self.gps.release(self)
 
-    def connect(self, callback):
-        "Send UBX debug packets to the given callback"
-        do_start = not self.callbacks
-        self.callbacks.add(callback)
-        if do_start:
-            self._start_listening()
-
-    def disconnect(self, callback):
-        "Stop sending UBX debug packets to the given callback"
-        if not self.callbacks: return
-        self.callbacks.discard(callback)
-        if not self.callbacks:
-            self._stop_listening()
-
-class GPSPosition():
+
+class GPSPosition(zavai.Service):
     def __init__(self, gps):
         self.gps = gps
-        self.callbacks = set()
 
     def on_position_changed(self, fields, tstamp, lat, lon, alt):
         zavai.info("gps position: position changed")
-        for c in self.callbacks:
-            c(fields, tstamp, lat, lon, alt)
+        self.notify(fields, tstamp, lat, lon, alt)
 
-    def _start_listening(self):
+    def start(self):
         self.gps.request(self)
         self.gps.bus.add_signal_receiver(
             self.on_position_changed, 'PositionChanged', 'org.freedesktop.Gypsy.Position',
             'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
 
-    def _stop_listening(self):
+    def stop(self):
         self.gps.bus.remove_signal_receiver(
             self.on_position_changed, 'PositionChanged', 'org.freedesktop.Gypsy.Position',
             'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
         self.gps.release(self)
 
-    def connect(self, callback):
-        "Send position changed messages to the given callback"
-        do_start = not self.callbacks
-        self.callbacks.add(callback)
-        if do_start:
-            self._start_listening()
-
-    def disconnect(self, callback):
-        "Stop sending position changed messages to the given callback"
-        if not self.callbacks: return
-        self.callbacks.discard(callback)
-        if not self.callbacks:
-            self._stop_listening()
-
-
 # For a list of dbus services, look in /etc/dbus-1/system.d/
-class GPS(zavai.Resource):
+class GPS(zavai.Service):
     def __init__(self, registry, name):
+        super(GPS, self).__init__()
+
         self.bus = registry.resource("dbus.system_bus")
 
         # see mdbus -s org.freesmartphone.ousaged /org/freesmartphone/Usage
@@ -162,30 +133,15 @@ class GPS(zavai.Resource):
         self.monitor = GPSMonitor(self)
         self.position = GPSPosition(self)
 
-        self.requestors = set()
-
-    def request(self, tag):
-        "Request usage of GPS by the subsystem with the given tag"
-        do_start = not self.requestors
-        self.requestors.add(tag)
-        if do_start:
-            # Request GPS resource
-            self.usage.RequestResource('GPS')
-            zavai.info("Acquired GPS")
-
-    def release(self, tag):
-        "Release usage of GPS by the subsystem with the given tag"
-        if not self.requestors: return
-        self.requestors.discard(tag)
-        if not self.requestors:
-            self.usage.ReleaseResource('GPS')
-            zavai.info("Released GPS")
-
-    def shutdown(self):
-        if self.requestors:
-            self.requestors.clear()
-            self.usage.ReleaseResource('GPS')
-            zavai.info("Released GPS")
+    def start(self):
+        """Request GPS resource"""
+        self.usage.RequestResource('GPS')
+        zavai.info("Acquired GPS")
+
+    def stop(self):
+        """Release usage of GPS"""
+        self.usage.ReleaseResource('GPS')
+        zavai.info("Released GPS")
 
 #    def wait_for_fix(self, callback):
 #        status = self.gps.GetFixStatus()
@@ -240,17 +196,17 @@ class GPS(zavai.Resource):
 #        self.audio.start_recording()
 #
 
-class GPX(zavai.Resource):
+class GPX(zavai.Service):
     "Write GPX track and waypoint files"
     def __init__(self, registry, name):
         self.registry = registry
         self.trk = None
         self.wpt = None
         self.last_pos = None
-        self.requestors = set()
         conf = registry.resource("conf")
         self.trackdir = conf.homedir
         self.activity_monitors = set()
+        self.started = False
 
     def add_activity_monitor(self, cb):
         self.activity_monitors.add(cb)
@@ -263,36 +219,33 @@ class GPX(zavai.Resource):
         for mon in self.activity_monitors:
             mon(self, self.last_pos is not None)
 
-    def request(self, tag):
-        "Request the GPX trace to be taken"
-        do_start = not self.requestors
-        self.requestors.add(tag)
-        if do_start:
-            zavai.info("Starting GPX trace subsystem")
-            gps = self.registry.resource("gps")
-            gps.position.connect(self.on_position_changed)
-
-    def release(self, tag):
-        "Release a GPX trace request"
-        if not self.requestors: return
-        self.requestors.discard(tag)
-        if not self.requestors:
-            zavai.info("Stopping GPX trace subsystem")
-            gps = self.registry.resource("gps")
-            gps.position.disconnect(self.on_position_changed)
-            self.stop()
+    def start(self):
+        zavai.info("Starting GPX trace subsystem")
+        self.started = True
+        gps = self.registry.resource("gps")
+        gps.position.connect(self.on_position_changed)
+
+    def stop(self):
+        if not self.started: return
+        zavai.info("Stopping GPX trace subsystem")
+        gps = self.registry.resource("gps")
+        gps.position.disconnect(self.on_position_changed)
+        self.stop_track()
+        self.started = False
 
     def on_position_changed(self, fields, tstamp, lat, lon, alt):
         self.last_pos = (fields, tstamp, lat, lon, alt)
         self.trackpoint()
 
-    def start(basename = None, tstamp = None):
+    def start_track(self, tstamp = None, basename = None):
         if basename is None:
+            self.basename = basename
+        elif tstamp is not None:
             # Compute basename for output files
-            basename = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(tstamp))
-            basename = os.path.join(self.trackdir, self.basename)
+            self.basename = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(tstamp))
+            self.basename = os.path.join(self.trackdir, self.basename)
 
-        self.trk = open(basename + "-trk.gpx", "wt")
+        self.trk = open(self.basename + "-trk.gpx", "wt")
         print >>self.trk, """<?xml version="1.0" encoding="UTF-8"?>
 <gpx
     version="1.0"
@@ -303,7 +256,7 @@ class GPX(zavai.Resource):
   <trk>
     <trkseg>""" % VERSION
 
-        self.wpt = open(basename + "-wpt.gpx", "wt")
+        self.wpt = open(self.basename + "-wpt.gpx", "wt")
         print >>self.wpt, """<?xml version="1.0" encoding="UTF-8"?>
 <gpx
     version="1.0"
@@ -315,7 +268,7 @@ class GPX(zavai.Resource):
         self.wpt_seq = 1;
         self.notify_activity_monitors()
 
-    def stop(self):
+    def stop_track(self):
         if self.trk is not None:
             print >>self.trk, "</trkseg></trk></gpx>"
             self.trk.close()
@@ -327,9 +280,6 @@ class GPX(zavai.Resource):
         self.last_pos = None
         self.notify_activity_monitors()
 
-    def shutdown(self):
-        self.stop()
-
     def trackpoint(self):
         "Mark a track point"
         if self.last_pos is None:
@@ -338,7 +288,7 @@ class GPX(zavai.Resource):
         fields, tstamp, lat, lon, ele = self.last_pos
 
         if not self.trk:
-            self.start(tstamp)
+            self.start_track(tstamp)
 
         print >>self.trk, """<trkpt lat="%f" lon="%f">
   <time>%s</time>
@@ -357,7 +307,7 @@ class GPX(zavai.Resource):
         fields, tstamp, lat, lon, ele = self.last_pos
 
         if not self.wpt:
-            self.start(tstamp)
+            self.start_track(tstamp)
 
         if name is None:
             name = "wpt_%d" % self.wpt_seq
index 4af413c83e9e02c9dd4a313ece374d507c70de67..285045f507ac3165f3e85221e0c4fe7041330fcf 100644 (file)
@@ -145,6 +145,9 @@ class Registry(object):
         self.objects.clear()
 
 class Resource(object):
+    def __init__(self):
+        super(Resource, self).__init__()
+
     def shutdown(self):
         """Shut down this resource.
 
@@ -155,3 +158,39 @@ class Resource(object):
         releasing a FSO resource, restoring mixer settings and so on.
         """
         pass
+
+class Service(Resource):
+    "Service that is activated only when someone is listening"
+    def __init__(self):
+        super(Service, self).__init__()
+        self.callbacks = set()
+
+    def shutdown(self):
+        self.stop()
+
+    def start(self):
+        "Activate the service"
+        pass
+
+    def stop(self):
+        "Deactivate the service"
+        pass
+
+    def notify(self, *args, **kw):
+        "Call all callbacks with the given parameters"
+        for cb in self.callbacks:
+            cb(*args, **kw)
+
+    def connect(self, callback):
+        "Connect a callback to this resource, activating it if needed"
+        do_start = not self.callbacks
+        self.callbacks.add(callback)
+        if do_start:
+            self.start()
+
+    def disconnect(self, callback):
+        "Disconnect a callback to this resource, activating it if needed"
+        if not self.callbacks: return
+        self.callbacks.discard(callback)
+        if not self.callbacks:
+            self.stop()