Convert Google plugin into a D-Bus service
[cinaest] / src / backends / google / google-backend.vala
diff --git a/src/backends/google/google-backend.vala b/src/backends/google/google-backend.vala
new file mode 100644 (file)
index 0000000..6a375b8
--- /dev/null
@@ -0,0 +1,189 @@
+using Gee;
+
+public Gee.HashMap <string, MovieSearch> searches;
+public DBus.Connection conn;
+
+[DBus (name = "org.maemo.cinaest.MovieSearch", signals="movies_found")]
+public class MovieSearch : Object {
+       public int id;
+       bool aborted;
+       string title;
+       GoogleParser parser;
+       GLib.List<GoogleMovie> results;
+       GoogleMovieService service;
+
+       // D-Bus API
+
+       public void abort () {
+               print ("aborting\n");
+               aborted = true;
+       }
+
+       public void start (string query) {
+               parser = new GoogleParser ();
+               title = query;
+
+               query_async.begin ();
+       }
+
+       public signal void movies_found (string[] movies, bool finished);
+
+       // Internal methods
+
+       internal MovieSearch (GoogleMovieService _service) {
+               service = _service;
+       }
+
+       private async void query_async () {
+               var gc = GConf.Client.get_default ();
+
+               results = new GLib.List<GoogleMovie> ();
+
+               string location = null;
+               try {
+                       location = gc.get_string ("/apps/cinaest/location");
+               } catch (Error e) {
+                       stdout.printf ("Error getting GConf option: %s\n", e.message);
+               }
+               if (location == null)
+                       location = "";
+
+               int n = yield parser.query (title, location, receive_movie);
+
+               try {
+                       var locations = ((SList<string>) gc.get_list ("/apps/cinaest/locations", GConf.ValueType.STRING)).copy ();
+                       if (insert_location_sorted (parser.location, ref locations)) {
+                               gc.set_list ("/apps/cinaest/locations", GConf.ValueType.STRING, locations);
+                       }
+                       if (location != parser.location) {
+                               location = parser.location;
+                               gc.set_string ("/apps/cinaest/location", location);
+                       }
+               } catch (Error e2) {
+                       stdout.printf ("GConf error: %s\n", e2.message);
+               }
+
+               print ("got %d movies\n", n);
+
+               var m = new string[results.length ()];
+               int i = 0;
+               for (unowned GLib.List<GoogleMovie> node = results.first (); node != null; node = node.next) {
+                       m[i++] = "{\"title\":\"%s\",\"rating\":%f,\"showtimes\":\"%s\",\"cinema_name\":\"%s\",\"cinema_phone\":\"%s\"}".printf (node.data.title, node.data.rating, node.data.showtimes, node.data.cinema.name, node.data.cinema.phone);
+               }
+               movies_found (m, true);
+               service.timeout_quit ();
+       }
+
+       private bool insert_location_sorted (string? location, ref SList<string> locations) {
+               if (location == null)
+                       return false;
+               if (locations != null) {
+                       for (unowned SList<string> l = locations; l != null; l = l.next) {
+                               if (l.data == location) {
+                                       return false;
+                               }
+                               if (l.data > location) {
+                                       l.insert (location, 0);
+                                       return true;
+                               }
+                       }
+               }
+               locations.append (location);
+               return true;
+       }
+
+       private void receive_movie (GoogleMovie movie) {
+       //      print ("received %s\n", movie.title);
+               results.append (movie);
+       }
+}
+
+[DBus (name = "org.maemo.cinaest.MovieService")]
+public class GoogleMovieService : Object {
+       private MainLoop loop;
+       private uint source_id;
+
+       // D-Bus API
+
+       public string new_search (DBus.BusName sender) {
+               print ("new search requested by %s\n", sender);
+               var search = new MovieSearch (this);
+
+               search.id = searches.size;
+               string path = "/org/maemo/cinaest/googleshowtimes/search%d".printf (search.id);
+               conn.register_object (path, search);
+
+               searches.set (path, search);
+
+               return path;
+       }
+
+       public void unregister (string path) {
+
+       print ("unregistering %s\n", path);
+               searches.remove (path);
+               print ("%d\n", searches.size);
+       }
+
+       // Internal methods
+
+       internal GoogleMovieService () {
+               loop = new MainLoop (null);
+       }
+
+       internal void timeout_quit () {
+               // With every change we reset the timer to 3min
+               if (source_id != 0) {
+                       Source.remove (source_id);
+               }
+               source_id = Timeout.add_seconds (180, quit);
+       }
+
+       private bool quit () {
+               loop.quit ();
+
+                // One-shot only
+                return false;
+        }
+
+       internal void run () {
+               loop.run ();
+       }
+}
+
+void on_client_lost (DBus.Object sender, string name, string prev, string newp) {
+       if (newp == "") {
+               // We lost a client
+               print ("lost a client: prev:%s\n", prev);
+               searches.remove (prev);
+       }
+}
+
+void main () {
+       var loop = new MainLoop (null, false);
+
+       try {
+               conn = DBus.Bus.get (DBus.BusType. SESSION);
+
+               searches = new Gee.HashMap <string, MovieSearch> ();
+
+               dynamic DBus.Object bus = conn.get_object ("org.freedesktop.DBus",
+                                                          "/org/freedesktop/DBus",
+                                                          "org.freedesktop.DBus");
+
+               uint res = bus.request_name ("org.maemo.cinaest.GoogleShowtimes", (uint) 0);
+
+               if (res == DBus.RequestNameReply.PRIMARY_OWNER) {
+                       var server = new GoogleMovieService ();
+
+                       conn.register_object ("/org/maemo/cinaest/movies", server);
+
+                       bus.NameOwnerChanged.connect (on_client_lost);
+
+                       server.timeout_quit ();
+                       server.run ();
+               }
+       } catch (Error e) {
+               stderr.printf ("Oops: %s\n", e.message);
+       }
+}