]> ToastFreeware Gitweb - gregoa/zavai.git/blobdiff - src/core.vala
Merge branch 'master' into gregoa
[gregoa/zavai.git] / src / core.vala
index 2cb23ecb5cae701d92a81b59916608da4cad70a5..2e2191550fcb8d7a948b4538d7fd509a7f34f721 100644 (file)
  */
 
 using GLib;
-using Gee;
 
 namespace zavai {
 
 public interface Resource : Object {
-        /**
-        * Shut down this resource.
-         *
-         * Normally one does nothing here, but it is important to give resources a
-         * chance to do cleanup when the program quits.
-         
-         * This can be used for tasks like closing the tags on a GPX track,
-         * releasing a FSO resource, restoring mixer settings and so on.
-         */
-       public abstract void shutdown();
+    /**
+     * Shut down this resource.
+     *
+     * Normally one does nothing here, but it is important to give resources a
+     * chance to do cleanup when the program quits.
+     * 
+     * This can be used for tasks like closing the tags on a GPX track,
+     * releasing a FSO resource, restoring mixer settings and so on.
+     */
+    public abstract void shutdown();
 }
 
 public abstract class Service : Object, Resource {
-       public string name { get; construct; }
-
-       bool _started;
-       public bool started {
-               get { return _started; }
-               set { _started = value; }
-               default = false;
-       }
-
-       public signal void toggled(bool new_state);
-
-       protected HashMap<string, int> requests;
-
-       construct {
-               requests = new HashMap<string, int>(str_hash, str_equal);
-       }
-
-       public void shutdown()
-       {
-               stop();
-       }
-
-       /// Activate the service
-       protected virtual void start()
-       {
-               if (!started)
-               {
-                       zavai.log.info("Service " + name + " started\n");
-                       started = true;
-                       toggled(started);
-               }
-       }
-
-       /// Deactivate the service
-       protected virtual void stop()
-       {
-               if (started)
-               {
-                       zavai.log.info("Service " + name + " stopped\n");
-                       started = false;
-                       toggled(started);
-               }
-       }
-
-       /**
-         Request a resource using the given ID.
-        *
-        * If it is the first time the resource is requested, start it and
-        * return true. Else, take note of the request and return false.
-        *
-        * If a resource is requested multiple times with the same ID, it will
-        * need to be released multiple times with that ID.
-        */
-       public bool request(string id)
-       {
-               bool res = (requests.size == 0);
-               if (id in requests)
-                       requests[id] = requests[id] + 1;
-               else
-                       requests.set(id, 1);
-               if (res) start();
-               return res;
-       }
-
-       /**
-        * Release a resource using the given ID.
-        *
-        * If after the call nothing is requesting the resource, stop it and
-        * return true. Else, take note of the release and return false.
-        *
-        * If a resource is requested multiple times with the same ID, it will
-        * need to be released multiple times with that ID.
-        */
-       public bool release(string id)
-       {
-               if (id in requests)
-               {
-                       if (requests[id] > 1)
-                               requests[id] = requests[id] - 1;
-                       else
-                               requests.remove(id);
-               } else {
-                       return false;
-               }
-               if (requests.size > 0)
-                       return false;
-               stop();
-               return true;
-       }
+    public string name { get; construct; }
+
+    bool _started;
+    public bool started {
+        get { return _started; }
+        set { _started = value; }
+    }
+
+    public signal void toggled(bool new_state);
+
+    protected class Request
+    {
+        public string requestor;
+        public int count;
+        public Request(string requestor)
+        {
+            this.requestor = requestor;
+            count = 1;
+        }
+    }
+
+    protected List<Request> requests;
+
+    construct
+    {
+        started = false;
+        requests = null;
+        zavai.registry.register(this);
+    }
+
+    public void shutdown()
+    {
+        stop();
+    }
+
+    /// Activate the service
+    protected virtual void start()
+    {
+        if (!started)
+        {
+            zavai.log.info("Service " + name + " started\n");
+            started = true;
+            toggled(started);
+        }
+    }
+
+    /// Deactivate the service
+    protected virtual void stop()
+    {
+        if (started)
+        {
+            zavai.log.info("Service " + name + " stopped\n");
+            started = false;
+            toggled(started);
+        }
+    }
+
+    /**
+      Request a resource using the given ID.
+     *
+     * If it is the first time the resource is requested, start it and
+     * return true. Else, take note of the request and return false.
+     *
+     * If a resource is requested multiple times with the same ID, it will
+     * need to be released multiple times with that ID.
+     */
+    public bool request(string id)
+    {
+        bool res = (requests == null);
+        bool got = false;
+        for (weak List<Request> i = requests; i != null; i = i.next)
+            if (i.data.requestor == id)
+            {
+                ++i.data.count;
+                got = true;
+                break;
+            }
+        if (!got)
+            requests.prepend(new Request(id));
+        if (res) start();
+        return res;
+    }
+
+    /**
+     * Release a resource using the given ID.
+     *
+     * If after the call nothing is requesting the resource, stop it and
+     * return true. Else, take note of the release and return false.
+     *
+     * If a resource is requested multiple times with the same ID, it will
+     * need to be released multiple times with that ID.
+     */
+    public bool release(string id)
+    {
+        weak List<Request> el = null;
+        for (weak List<Request> i = requests; i != null; i = i.next)
+            if (i.data.requestor == id)
+            {
+                el = i;
+                break;
+            }
+
+        if (el == null)
+            return false;
+
+        ++el.data.count;
+        if (el.data.count == 0)
+            requests.delete_link(el);
+
+        if (requests != null)
+            return false;
+
+        stop();
+        return true;
+    }
+}
+
+public abstract class ScriptService : Service
+{
+    protected string script;
+
+    protected bool script_start()
+    {
+        try {
+            zavai.config.find_and_run_script(name, "start");
+            return true;
+        } catch (Error e) {
+            zavai.log.error("Running " + name + " start: " + e.message);
+            return false;
+        }
+    }
+
+    protected bool script_stop()
+    {
+        try {
+            zavai.config.find_and_run_script(name, "stop");
+            return true;
+        } catch (Error e) {
+            zavai.log.error("Running " + name + " stop: " + e.message);
+            return false;
+        }
+    }
+
+    protected bool script_status()
+    {
+        string std_out;
+        string std_err;
+        string script = zavai.config.find_script(name);
+        if (script == null)
+        {
+            zavai.log.error("Hook " + name + " does not exist");
+            return false;
+        }
+        string command = script + " status";
+        try {
+            int res = zavai.config.run_script_sync(command, out std_out, out std_err);
+            if (res != 0)
+            {
+                zavai.log.error("Running " + command + ": " + std_err);
+                return false;
+            }
+        } catch (SpawnError e) {
+            zavai.log.error("Running " + command + ": " + e.message);
+            return false;
+        }
+
+        std_out._strip();
+
+        return (std_out == "on");
+    }
+}
+
+public abstract class ScriptMonitorService : Service
+{
+    protected Pid child_pid;
+    protected int child_watch_id;
+
+    ScriptMonitorService()
+    {
+        child_pid = 0;
+        child_watch_id = 0;
+    }
+
+    protected bool script_start()
+    {
+        string script = zavai.config.find_script(name);
+        zavai.log.info("Run program: " + script + " pre");
+        try {
+            // Then run our own script
+            zavai.config.run_script(script + " pre");
+        } catch (Error e) {
+            zavai.log.error("Running " + script + " pre: " + e.message);
+            return false;
+        }
+
+        zavai.log.info("Run program: " + script + " run");
+        string[] args = { script, "run" };
+        try {
+            Process.spawn_async(
+                Environment.get_home_dir(),
+                args,
+                null,
+                SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
+                null,
+                out child_pid);
+        } catch (SpawnError e) {
+            zavai.log.error("Running " + script + " run: " + e.message);
+            return false;
+        }
+
+        // Add a child watch source to know when it ends
+        ChildWatch.add(child_pid, on_child);
+
+        return true;
+    }
+
+    protected bool script_stop()
+    {
+        Posix.kill((Posix.pid_t)child_pid, Posix.SIGTERM);
+        return true;
+    }
+
+    protected void on_child(Pid pid, int status)
+    {
+        zavai.log.info("Exited");
+stderr.printf("STATUS %d\n", status);
+        Process.close_pid(pid);
+
+        try {
+            // Then run our own script
+            zavai.config.find_and_run_script(name, "post");
+        } catch (Error e) {
+            zavai.log.error("Running " + name + " post: " + e.message);
+            return;
+        }
+
+        cleanup_after_script_stop();
+
+        base.stop();
+    }
+
+    protected virtual void cleanup_after_script_stop()
+    {
+    }
+
+    /*
+    protected bool script_status()
+    {
+    }
+    */
 }
 
 }