Convert Google plugin into a D-Bus service
[cinaest] / src / backends / google / google-backend.vala
1 using Gee;
2
3 public Gee.HashMap <string, MovieSearch> searches;
4 public DBus.Connection conn;
5
6 [DBus (name = "org.maemo.cinaest.MovieSearch", signals="movies_found")]
7 public class MovieSearch : Object {
8         public int id;
9         bool aborted;
10         string title;
11         GoogleParser parser;
12         GLib.List<GoogleMovie> results;
13         GoogleMovieService service;
14
15         // D-Bus API
16
17         public void abort () {
18                 print ("aborting\n");
19                 aborted = true;
20         }
21
22         public void start (string query) {
23                 parser = new GoogleParser ();
24                 title = query;
25
26                 query_async.begin ();
27         }
28
29         public signal void movies_found (string[] movies, bool finished);
30
31         // Internal methods
32
33         internal MovieSearch (GoogleMovieService _service) {
34                 service = _service;
35         }
36
37         private async void query_async () {
38                 var gc = GConf.Client.get_default ();
39
40                 results = new GLib.List<GoogleMovie> ();
41
42                 string location = null;
43                 try {
44                         location = gc.get_string ("/apps/cinaest/location");
45                 } catch (Error e) {
46                         stdout.printf ("Error getting GConf option: %s\n", e.message);
47                 }
48                 if (location == null)
49                         location = "";
50
51                 int n = yield parser.query (title, location, receive_movie);
52
53                 try {
54                         var locations = ((SList<string>) gc.get_list ("/apps/cinaest/locations", GConf.ValueType.STRING)).copy ();
55                         if (insert_location_sorted (parser.location, ref locations)) {
56                                 gc.set_list ("/apps/cinaest/locations", GConf.ValueType.STRING, locations);
57                         }
58                         if (location != parser.location) {
59                                 location = parser.location;
60                                 gc.set_string ("/apps/cinaest/location", location);
61                         }
62                 } catch (Error e2) {
63                         stdout.printf ("GConf error: %s\n", e2.message);
64                 }
65
66                 print ("got %d movies\n", n);
67
68                 var m = new string[results.length ()];
69                 int i = 0;
70                 for (unowned GLib.List<GoogleMovie> node = results.first (); node != null; node = node.next) {
71                         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);
72                 }
73                 movies_found (m, true);
74                 service.timeout_quit ();
75         }
76
77         private bool insert_location_sorted (string? location, ref SList<string> locations) {
78                 if (location == null)
79                         return false;
80                 if (locations != null) {
81                         for (unowned SList<string> l = locations; l != null; l = l.next) {
82                                 if (l.data == location) {
83                                         return false;
84                                 }
85                                 if (l.data > location) {
86                                         l.insert (location, 0);
87                                         return true;
88                                 }
89                         }
90                 }
91                 locations.append (location);
92                 return true;
93         }
94
95         private void receive_movie (GoogleMovie movie) {
96         //      print ("received %s\n", movie.title);
97                 results.append (movie);
98         }
99 }
100
101 [DBus (name = "org.maemo.cinaest.MovieService")]
102 public class GoogleMovieService : Object {
103         private MainLoop loop;
104         private uint source_id;
105
106         // D-Bus API
107
108         public string new_search (DBus.BusName sender) {
109                 print ("new search requested by %s\n", sender);
110                 var search = new MovieSearch (this);
111
112                 search.id = searches.size;
113                 string path = "/org/maemo/cinaest/googleshowtimes/search%d".printf (search.id);
114                 conn.register_object (path, search);
115
116                 searches.set (path, search);
117
118                 return path;
119         }
120
121         public void unregister (string path) {
122
123         print ("unregistering %s\n", path);
124                 searches.remove (path);
125                 print ("%d\n", searches.size);
126         }
127
128         // Internal methods
129
130         internal GoogleMovieService () {
131                 loop = new MainLoop (null);
132         }
133
134         internal void timeout_quit () {
135                 // With every change we reset the timer to 3min
136                 if (source_id != 0) {
137                         Source.remove (source_id);
138                 }
139                 source_id = Timeout.add_seconds (180, quit);
140         }
141
142         private bool quit () {
143                 loop.quit ();
144
145                 // One-shot only
146                 return false;
147         }
148
149         internal void run () {
150                 loop.run ();
151         }
152 }
153
154 void on_client_lost (DBus.Object sender, string name, string prev, string newp) {
155         if (newp == "") {
156                 // We lost a client
157                 print ("lost a client: prev:%s\n", prev);
158                 searches.remove (prev);
159         }
160 }
161
162 void main () {
163         var loop = new MainLoop (null, false);
164
165         try {
166                 conn = DBus.Bus.get (DBus.BusType. SESSION);
167
168                 searches = new Gee.HashMap <string, MovieSearch> ();
169
170                 dynamic DBus.Object bus = conn.get_object ("org.freedesktop.DBus",
171                                                            "/org/freedesktop/DBus",
172                                                            "org.freedesktop.DBus");
173
174                 uint res = bus.request_name ("org.maemo.cinaest.GoogleShowtimes", (uint) 0);
175
176                 if (res == DBus.RequestNameReply.PRIMARY_OWNER) {
177                         var server = new GoogleMovieService ();
178
179                         conn.register_object ("/org/maemo/cinaest/movies", server);
180
181                         bus.NameOwnerChanged.connect (on_client_lost);
182
183                         server.timeout_quit ();
184                         server.run ();
185                 }
186         } catch (Error e) {
187                 stderr.printf ("Oops: %s\n", e.message);
188         }
189 }