build,core,plugins: Port to GDBus and GVariant
[profile/ivi/rygel.git] / src / plugins / external / rygel-external-plugin-factory.vala
1 /*
2  * Copyright (C) 2009 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>.
3  * Copyright (C) 2009,2010 Nokia Corporation.
4  *
5  * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
6  *                               <zeeshan.ali@nokia.com>
7  *
8  * This file is part of Rygel.
9  *
10  * Rygel is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * Rygel is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24
25 using Rygel;
26 using Gee;
27 using FreeDesktop;
28
29 private External.PluginFactory plugin_factory;
30
31 public void module_init (PluginLoader loader) {
32     try {
33         plugin_factory = new External.PluginFactory (loader);
34     } catch (IOError error) {
35         critical ("Failed to fetch list of external services: %s\n",
36                 error.message);
37     }
38 }
39
40 public class Rygel.External.PluginFactory {
41     private const string SERVICE_PREFIX = "org.gnome.UPnP.MediaServer2.";
42     private const string GRILO_UPNP_PREFIX = SERVICE_PREFIX + "grl_upnp";
43
44     DBusObject   dbus_obj;
45     PluginLoader loader;
46     IconFactory  icon_factory;
47
48     public PluginFactory (PluginLoader loader) throws IOError {
49         this.icon_factory = new IconFactory ();
50
51         this.dbus_obj = Bus.get_proxy_sync (BusType.SESSION,
52                                             DBUS_SERVICE,
53                                             DBUS_OBJECT);
54         this.loader = loader;
55
56         this.load_plugins.begin ();
57     }
58
59     private async void load_plugins () throws IOError {
60         var services = yield this.dbus_obj.list_names ();
61
62         foreach (var service in services) {
63             if (service.has_prefix (SERVICE_PREFIX) &&
64                 this.loader.get_plugin_by_name (service) == null) {
65                 yield this.load_plugin_n_handle_error (service);
66             }
67         }
68
69         yield this.load_activatable_plugins ();
70     }
71
72     private async void load_activatable_plugins () throws IOError {
73         var services = yield this.dbus_obj.list_activatable_names ();
74
75         foreach (var service in services) {
76             if (service.has_prefix (SERVICE_PREFIX) &&
77                 this.loader.get_plugin_by_name (service) == null) {
78                 yield this.load_plugin_n_handle_error (service);
79             }
80         }
81
82         this.dbus_obj.name_owner_changed.connect (this.name_owner_changed);
83     }
84
85     private void name_owner_changed (DBusObject dbus_obj,
86                                      string     name,
87                                      string     old_owner,
88                                      string     new_owner) {
89         var plugin = this.loader.get_plugin_by_name (name);
90
91         if (plugin != null) {
92             if (old_owner != "" && new_owner == "") {
93                 debug ("Service '%s' going down, marking it as unavailable",
94                        name);
95                 plugin.available = false;
96             } else if (old_owner == "" && new_owner != "") {
97                 debug ("Service '%s' up again, marking it as available", name);
98                 plugin.available = true;
99             }
100         } else if (name.has_prefix (SERVICE_PREFIX)) {
101             // Ah, new plugin available, lets use it
102             this.load_plugin_n_handle_error.begin (name);
103         }
104     }
105
106     private async void load_plugin_n_handle_error (string service_name) {
107         try {
108             yield this.load_plugin (service_name);
109         } catch (IOError error) {
110             warning ("Failed to load external plugin '%s': %s",
111                      service_name,
112                      error.message);
113         }
114     }
115
116     private async void load_plugin (string service_name) throws IOError {
117         if (service_name.has_prefix (GRILO_UPNP_PREFIX)) {
118             // We don't entertain UPnP sources
119             return;
120         }
121
122         // org.gnome.UPnP.MediaServer1.NAME => /org/gnome/UPnP/MediaServer1/NAME
123         var root_object = "/" + service_name.replace (".", "/");
124
125         // Create proxy to MediaObject iface to get the display name through
126         Properties props = Bus.get_proxy_sync (BusType.SESSION,
127                                                service_name,
128                                                root_object);
129
130         HashTable<string,Variant> object_props;
131         HashTable<string,Variant> container_props;
132
133         object_props = yield props.get_all (MediaObjectProxy.IFACE);
134         container_props = yield props.get_all (MediaContainerProxy.IFACE);
135
136         var icon = yield this.icon_factory.create (service_name,
137                                                    container_props);
138
139         string title;
140         var value = object_props.lookup ("DisplayName");
141         if (value != null) {
142             title = (string) value;
143         } else {
144             title = service_name;
145         }
146
147         var child_count = (uint) container_props.lookup ("ChildCount");
148         var searchable = (bool) container_props.lookup ("Searchable");
149
150         var plugin = new External.Plugin (service_name,
151                                           title,
152                                           child_count,
153                                           searchable,
154                                           root_object,
155                                           icon);
156
157         this.loader.add_plugin (plugin);
158     }
159 }