xref: /haiku/src/servers/index/IndexServer.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
1 /*
2  * Copyright 2010-2013 Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		John Scipione, jscipione@gmail.com
7  *		Clemens Zeidler, haiku@clemens-zeidler.de
8  */
9 
10 
11 #include "IndexServer.h"
12 
13 #include <Path.h>
14 #include <String.h>
15 
16 
17 VolumeObserverHandler::VolumeObserverHandler(IndexServer* indexServer)
18 	:
19 	fIndexServer(indexServer)
20 {
21 
22 }
23 
24 
25 void
26 VolumeObserverHandler::MessageReceived(BMessage* message)
27 {
28 	if (message->what != B_NODE_MONITOR)
29 		return;
30 
31 	dev_t device;
32 	int32 opcode;
33 	message->FindInt32("opcode", &opcode) ;
34 	switch (opcode) {
35 		case B_DEVICE_MOUNTED :
36 			message->FindInt32("new device", &device);
37 			fIndexServer->AddVolume(BVolume(device));
38 			break ;
39 
40 		case B_DEVICE_UNMOUNTED :
41 			message->FindInt32("device", &device);
42 			fIndexServer->RemoveVolume(BVolume(device));
43 			break ;
44 	}
45 }
46 
47 
48 AnalyserMonitorHandler::AnalyserMonitorHandler(IndexServer* indexServer)
49 	:
50 	fIndexServer(indexServer)
51 {
52 
53 }
54 
55 
56 void
57 AnalyserMonitorHandler::AddOnEnabled(const add_on_entry_info* entryInfo)
58 {
59 	entry_ref ref;
60 	make_entry_ref(entryInfo->dir_nref.device, entryInfo->dir_nref.node,
61 		entryInfo->name, &ref);
62 	fIndexServer->RegisterAddOn(ref);
63 };
64 
65 
66 void
67 AnalyserMonitorHandler::AddOnDisabled(const add_on_entry_info* entryInfo)
68 {
69 	entry_ref ref;
70 	make_entry_ref(entryInfo->dir_nref.device, entryInfo->dir_nref.node,
71 		entryInfo->name, &ref);
72 	fIndexServer->UnregisterAddOn(ref);
73 };
74 
75 
76 IndexServer::IndexServer()
77 	:
78 	BApplication("application/x-vnd.Haiku-index_server"),
79 	fVolumeObserverHandler(this),
80 	fAddOnMonitorHandler(this),
81 	fPulseRunner(NULL)
82 {
83 	AddHandler(&fVolumeObserverHandler);
84 	AddHandler(&fAddOnMonitorHandler);
85 }
86 
87 
88 IndexServer::~IndexServer()
89 {
90 	for (int i = 0; i < fAddOnList.CountItems(); i++) {
91 		IndexServerAddOn* addon = fAddOnList.ItemAt(i);
92 		for (int i = 0; i < fVolumeWatcherList.CountItems(); i++)
93 			fVolumeWatcherList.ItemAt(i)->RemoveAnalyser(addon->Name());
94 		image_id image = addon->ImageId();
95 		delete addon;
96 		unload_add_on(image);
97 	}
98 
99 	_StopWatchingVolumes();
100 
101 	delete fPulseRunner;
102 
103 	RemoveHandler(&fVolumeObserverHandler);
104 	RemoveHandler(&fAddOnMonitorHandler);
105 }
106 
107 
108 void
109 IndexServer::ReadyToRun()
110 {
111 	_StartWatchingAddOns();
112 	_StartWatchingVolumes();
113 }
114 
115 
116 void
117 IndexServer::MessageReceived(BMessage *message)
118 {
119 	BApplication::MessageReceived(message);
120 }
121 
122 
123 bool
124 IndexServer::QuitRequested()
125 {
126 	_StopWatchingVolumes();
127 	return BApplication::QuitRequested();
128 }
129 
130 
131 void
132 IndexServer::AddVolume(const BVolume& volume)
133 {
134 	// ignore volumes like / or /dev
135 	if (volume.Capacity() == 0)
136 		return;
137 
138 	// check if volume is already in our list
139 	for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
140 		VolumeWatcher* current = fVolumeWatcherList.ItemAt(i);
141 		if (current->Volume() == volume)
142 			return;
143 	}
144 
145 	char name[256];
146 	volume.GetName(name);
147 	STRACE("IndexServer::AddVolume %s\n", name);
148 
149 	VolumeWatcher* watcher = new VolumeWatcher(volume);
150 /*	if (!watcher->Enabled()) {
151 		delete watcher;
152 		return;
153 	}*/
154 	fVolumeWatcherList.AddItem(watcher);
155 	_SetupVolumeWatcher(watcher);
156 	watcher->StartWatching();
157 }
158 
159 
160 void
161 IndexServer::RemoveVolume(const BVolume& volume)
162 {
163 	VolumeWatcher* watcher = NULL;
164 	for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
165 		VolumeWatcher* current = fVolumeWatcherList.ItemAt(i);
166 		if (current->Volume() == volume) {
167 			watcher = current;
168 			break;
169 		}
170 	}
171 
172 	if (!watcher)
173 		return;
174 
175 	watcher->Stop();
176 	fVolumeWatcherList.RemoveItem(watcher);
177 	watcher->PostMessage(B_QUIT_REQUESTED);
178 }
179 
180 
181 void
182 IndexServer::RegisterAddOn(entry_ref ref)
183 {
184 	STRACE("RegisterAddOn %s\n", ref.name);
185 
186 	BPath path(&ref);
187 	image_id image = load_add_on(path.Path());
188 	if (image < 0)
189 		return;
190 
191 	create_index_server_addon* createFunc;
192 
193 	// Get the instantiation function
194 	status_t status = get_image_symbol(image, "instantiate_index_server_addon",
195 		B_SYMBOL_TYPE_TEXT, (void**)&createFunc);
196 	if (status != B_OK) {
197 		unload_add_on(image);
198 		return;
199 	}
200 
201 	IndexServerAddOn* addon = createFunc(image, ref.name);
202 	if (!addon) {
203 		unload_add_on(image);
204 		return;
205 	}
206 	if (!fAddOnList.AddItem(addon)) {
207 		unload_add_on(image);
208 		return;
209 	}
210 
211 	for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
212 		VolumeWatcher* watcher = fVolumeWatcherList.ItemAt(i);
213 		FileAnalyser* analyser = _SetupFileAnalyser(addon, watcher->Volume());
214 		if (!analyser)
215 			continue;
216 		if (!watcher->AddAnalyser(analyser))
217 			delete analyser;
218 	}
219 
220 }
221 
222 
223 void
224 IndexServer::UnregisterAddOn(entry_ref ref)
225 {
226 	IndexServerAddOn* addon = _FindAddon(ref.name);
227 	if (!addon)
228 		return;
229 
230 	for (int i = 0; i < fVolumeWatcherList.CountItems(); i++)
231 		fVolumeWatcherList.ItemAt(i)->RemoveAnalyser(addon->Name());
232 
233 	fAddOnList.RemoveItem(addon);
234 	unload_add_on(addon->ImageId());
235 	delete addon;
236 }
237 
238 
239 FileAnalyser*
240 IndexServer::CreateFileAnalyser(const BString& name, const BVolume& volume)
241 {
242 	Lock();
243 	IndexServerAddOn* addon = _FindAddon(name);
244 	if (!addon) {
245 		Unlock();
246 		return NULL;
247 	}
248 	FileAnalyser* analyser = addon->CreateFileAnalyser(volume);
249 	Unlock();
250 	return analyser;
251 }
252 
253 
254 void
255 IndexServer::_StartWatchingVolumes()
256 {
257 	BVolume volume;
258 	while (fVolumeRoster.GetNextVolume(&volume) != B_BAD_VALUE)
259 		AddVolume(volume);
260 	fVolumeRoster.StartWatching(this);
261 }
262 
263 
264 void
265 IndexServer::_StopWatchingVolumes()
266 {
267 	STRACE("_StopWatchingVolumes\n");
268 
269 	for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
270 		VolumeWatcher* watcher = fVolumeWatcherList.ItemAt(i);
271 		watcher->Stop();
272 		watcher->PostMessage(B_QUIT_REQUESTED);
273 	}
274 	fVolumeWatcherList.MakeEmpty();
275 }
276 
277 
278 void
279 IndexServer::_SetupVolumeWatcher(VolumeWatcher* watcher)
280 {
281 	for (int i = 0; i < fAddOnList.CountItems(); i++) {
282 		IndexServerAddOn* addon = fAddOnList.ItemAt(i);
283 		FileAnalyser* analyser = _SetupFileAnalyser(addon, watcher->Volume());
284 		if (!analyser)
285 			continue;
286 		if (!watcher->AddAnalyser(analyser))
287 			delete analyser;
288 	}
289 }
290 
291 
292 FileAnalyser*
293 IndexServer::_SetupFileAnalyser(IndexServerAddOn* addon, const BVolume& volume)
294 {
295 	FileAnalyser* analyser = addon->CreateFileAnalyser(volume);
296 	if (!analyser)
297 		return NULL;
298 	AnalyserSettings* settings = new AnalyserSettings(analyser->Name(),
299 		analyser->Volume());
300 	BReference<AnalyserSettings> settingsRef(settings, true);
301 	if (!settings) {
302 		delete analyser;
303 		return NULL;
304 	}
305 	analyser->SetSettings(settings);
306 	return analyser;
307 }
308 
309 
310 void
311 IndexServer::_StartWatchingAddOns()
312 {
313 	AddHandler(&fAddOnMonitorHandler);
314 
315 	BMessage pulse(B_PULSE);
316 	fPulseRunner = new BMessageRunner(&fAddOnMonitorHandler, &pulse, 1000000LL);
317 		// the monitor handler needs a pulse to check if add-ons are ready
318 
319 	fAddOnMonitorHandler.AddAddOnDirectories("index_server");
320 }
321 
322 
323 IndexServerAddOn*
324 IndexServer::_FindAddon(const BString& name)
325 {
326 	for (int i = 0; i < fAddOnList.CountItems(); i++) {
327 		IndexServerAddOn* current = fAddOnList.ItemAt(i);
328 		if (current->Name() == name)
329 			return current;
330 	}
331 	return NULL;
332 }
333