core: Make the device unavailable before removing
[profile/ivi/rygel.git] / src / rygel / rygel-main.vala
1 /*
2  * Copyright (C) 2008 Nokia Corporation.
3  * Copyright (C) 2008 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>.
4  *
5  * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
6  *
7  * This file is part of Rygel.
8  *
9  * Rygel is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Rygel is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  */
23
24 using CStuff;
25 using Gee;
26 using GUPnP;
27
28 public class Rygel.Main : Object {
29     private PluginLoader plugin_loader;
30     private ContextManager context_manager;
31     private ArrayList <RootDeviceFactory> factories;
32     private ArrayList <RootDevice> root_devices;
33
34     private Configuration config;
35
36     private MainLoop main_loop;
37
38     private int exit_code;
39
40     public Main () throws GLib.Error {
41         Environment.set_application_name (_(BuildConfig.PACKAGE_NAME));
42
43         this.config = MetaConfig.get_default ();
44         this.plugin_loader = new PluginLoader ();
45         this.root_devices = new ArrayList <RootDevice> ();
46         this.factories = new ArrayList <RootDeviceFactory> ();
47         this.context_manager = this.create_context_manager ();
48         this.main_loop = new GLib.MainLoop (null, false);
49
50         this.exit_code = 0;
51
52         this.plugin_loader.plugin_available += this.on_plugin_loaded;
53
54         Utils.on_application_exit (this.application_exit_cb);
55     }
56
57     public int run () {
58         this.plugin_loader.load_plugins ();
59
60         this.main_loop.run ();
61
62         return this.exit_code;
63     }
64
65     public void exit (int exit_code) {
66         this.exit_code = exit_code;
67         this.main_loop.quit ();
68     }
69
70     private void application_exit_cb () {
71         this.exit (0);
72     }
73
74     private void on_plugin_loaded (PluginLoader plugin_loader,
75                                    Plugin       plugin) {
76         foreach (var factory in this.factories) {
77             this.create_device (plugin, factory);
78         }
79     }
80
81     private ContextManager create_context_manager () {
82         int port = 0;
83
84         try {
85             port = this.config.get_port ();
86         } catch (GLib.Error err) {}
87
88         var manager = new ContextManager (null, port);
89
90         manager.context_available.connect (this.on_context_available);
91         manager.context_unavailable.connect (this.on_context_unavailable);
92
93         return manager;
94     }
95
96     private void on_context_available (GUPnP.ContextManager manager,
97                                        GUPnP.Context        context) {
98         string host_ip = null;
99
100         debug ("new network context %s (%s) available.",
101                context.name,
102                context.host_ip);
103
104         try {
105             host_ip = this.config.get_host_ip ();
106         } catch (GLib.Error err) {}
107
108         if (host_ip == null || host_ip == context.host_ip) {
109             var factory = new RootDeviceFactory (context);
110
111             foreach (var plugin in this.plugin_loader.list_plugins ()) {
112                 this.create_device (plugin, factory);
113             }
114
115             this.factories.add (factory);
116
117             // Host UPnP dir
118             context.host_path (BuildConfig.DATA_DIR, "");
119         } else {
120             debug ("Ignoring network context %s (%s).",
121                    context.name,
122                    context.host_ip);
123         }
124     }
125
126     private void on_context_unavailable (GUPnP.ContextManager manager,
127                                          GUPnP.Context        context) {
128         debug ("Network context %s (%s) now unavailable.",
129                context.name,
130                context.host_ip);
131
132         var factory_list = new ArrayList <RootDeviceFactory> ();
133         foreach (var factory in this.factories) {
134             if (context == factory.context) {
135                 factory_list.add (factory);
136             }
137         }
138
139         foreach (var factory in factory_list) {
140             this.factories.remove (factory);
141         }
142
143         var device_list = new ArrayList <RootDevice> ();
144         foreach (var device in this.root_devices) {
145             if (context == device.context) {
146                 device_list.add (device);
147             }
148         }
149
150         foreach (var device in device_list) {
151             device.available = false;
152             this.root_devices.remove (device);
153         }
154     }
155
156     private void create_device (Plugin            plugin,
157                                 RootDeviceFactory factory) {
158         try {
159             var device = factory.create (plugin);
160
161             device.available = plugin.available;
162
163             this.root_devices.add (device);
164
165             plugin.notify["available"] += this.on_plugin_notify;
166         } catch (GLib.Error error) {
167             warning ("Failed to create RootDevice for %s. Reason: %s\n",
168                     plugin.name,
169                     error.message);
170         }
171     }
172
173     private void on_plugin_notify (Plugin    plugin,
174                                    ParamSpec spec) {
175         foreach (var device in this.root_devices) {
176             if (device.resource_factory == plugin) {
177                 device.available = plugin.available;
178             }
179         }
180     }
181
182     public static int main (string[] args) {
183         Main main;
184         DBusService service;
185
186         try {
187             // Parse commandline options
188             CmdlineConfig.parse_args (ref args);
189
190             // initialize gstreamer
191             var dummy_args = new string[0];
192             Gst.init (ref dummy_args);
193
194             main = new Main ();
195             service = new DBusService (main);
196         } catch (CmdlineConfigError.VERSION_ONLY err) {
197             return 0;
198         } catch (GLib.Error err) {
199             error ("%s", err.message);
200
201             return -1;
202         }
203
204         int exit_code = main.run ();
205
206         return exit_code;
207     }
208 }
209