xref: /haiku/src/servers/index/IndexServer.cpp (revision a3e794ae459fec76826407f8ba8c94cd3535f128)
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 
80 	fVolumeObserverHandler(this),
81 	fAddOnMonitorHandler(this),
82 	fPulseRunner(NULL)
83 {
84 	AddHandler(&fVolumeObserverHandler);
85 	AddHandler(&fAddOnMonitorHandler);
86 }
87 
88 
89 IndexServer::~IndexServer()
90 {
91 	for (int i = 0; i < fAddOnList.CountItems(); i++) {
92 		IndexServerAddOn* addon = fAddOnList.ItemAt(i);
93 		for (int i = 0; i < fVolumeWatcherList.CountItems(); i++)
94 			fVolumeWatcherList.ItemAt(i)->RemoveAnalyser(addon->Name());
95 		image_id image = addon->ImageId();
96 		delete addon;
97 		unload_add_on(image);
98 	}
99 
100 	_StopWatchingVolumes();
101 
102 	delete fPulseRunner;
103 
104 	RemoveHandler(&fVolumeObserverHandler);
105 	RemoveHandler(&fAddOnMonitorHandler);
106 }
107 
108 
109 void
110 IndexServer::ReadyToRun()
111 {
112 	_StartWatchingAddOns();
113 	_StartWatchingVolumes();
114 }
115 
116 
117 void
118 IndexServer::MessageReceived(BMessage *message)
119 {
120 	BApplication::MessageReceived(message);
121 }
122 
123 
124 bool
125 IndexServer::QuitRequested()
126 {
127 	_StopWatchingVolumes();
128 	return BApplication::QuitRequested();
129 }
130 
131 
132 void
133 IndexServer::AddVolume(const BVolume& volume)
134 {
135 	// ignore volumes like / or /dev
136 	if (volume.Capacity() == 0)
137 		return;
138 
139 	// check if volume is already in our list
140 	for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
141 		VolumeWatcher* current = fVolumeWatcherList.ItemAt(i);
142 		if (current->Volume() == volume)
143 			return;
144 	}
145 
146 	char name[256];
147 	volume.GetName(name);
148 	STRACE("IndexServer::AddVolume %s\n", name);
149 
150 	VolumeWatcher* watcher = new VolumeWatcher(volume);
151 /*	if (!watcher->Enabled()) {
152 		delete watcher;
153 		return;
154 	}*/
155 	fVolumeWatcherList.AddItem(watcher);
156 	_SetupVolumeWatcher(watcher);
157 	watcher->StartWatching();
158 }
159 
160 
161 void
162 IndexServer::RemoveVolume(const BVolume& volume)
163 {
164 	VolumeWatcher* watcher = NULL;
165 	for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
166 		VolumeWatcher* current = fVolumeWatcherList.ItemAt(i);
167 		if (current->Volume() == volume) {
168 			watcher = current;
169 			break;
170 		}
171 	}
172 
173 	if (!watcher)
174 		return;
175 
176 	watcher->Stop();
177 	fVolumeWatcherList.RemoveItem(watcher);
178 	watcher->PostMessage(B_QUIT_REQUESTED);
179 }
180 
181 
182 void
183 IndexServer::RegisterAddOn(entry_ref ref)
184 {
185 	STRACE("RegisterAddOn %s\n", ref.name);
186 
187 	BPath path(&ref);
188 	image_id image = load_add_on(path.Path());
189 	if (image < 0)
190 		return;
191 
192 	create_index_server_addon* createFunc;
193 
194 	// Get the instantiation function
195 	status_t status = get_image_symbol(image, "instantiate_index_server_addon",
196 		B_SYMBOL_TYPE_TEXT, (void**)&createFunc);
197 	if (status != B_OK) {
198 		unload_add_on(image);
199 		return;
200 	}
201 
202 	IndexServerAddOn* addon = createFunc(image, ref.name);
203 	if (!addon) {
204 		unload_add_on(image);
205 		return;
206 	}
207 	if (!fAddOnList.AddItem(addon)) {
208 		unload_add_on(image);
209 		return;
210 	}
211 
212 	for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
213 		VolumeWatcher* watcher = fVolumeWatcherList.ItemAt(i);
214 		FileAnalyser* analyser = _SetupFileAnalyser(addon, watcher->Volume());
215 		if (!analyser)
216 			continue;
217 		if (!watcher->AddAnalyser(analyser))
218 			delete analyser;
219 	}
220 
221 }
222 
223 
224 void
225 IndexServer::UnregisterAddOn(entry_ref ref)
226 {
227 	IndexServerAddOn* addon = _FindAddon(ref.name);
228 	if (!addon)
229 		return;
230 
231 	for (int i = 0; i < fVolumeWatcherList.CountItems(); i++)
232 		fVolumeWatcherList.ItemAt(i)->RemoveAnalyser(addon->Name());
233 
234 	fAddOnList.RemoveItem(addon);
235 	unload_add_on(addon->ImageId());
236 	delete addon;
237 }
238 
239 
240 FileAnalyser*
241 IndexServer::CreateFileAnalyser(const BString& name, const BVolume& volume)
242 {
243 	Lock();
244 	IndexServerAddOn* addon = _FindAddon(name);
245 	if (!addon) {
246 		Unlock();
247 		return NULL;
248 	}
249 	FileAnalyser* analyser = addon->CreateFileAnalyser(volume);
250 	Unlock();
251 	return analyser;
252 }
253 
254 
255 void
256 IndexServer::_StartWatchingVolumes()
257 {
258 	BVolume volume;
259 	while (fVolumeRoster.GetNextVolume(&volume) != B_BAD_VALUE)
260 		AddVolume(volume);
261 	fVolumeRoster.StartWatching(this);
262 }
263 
264 
265 void
266 IndexServer::_StopWatchingVolumes()
267 {
268 	STRACE("_StopWatchingVolumes\n");
269 
270 	for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
271 		VolumeWatcher* watcher = fVolumeWatcherList.ItemAt(i);
272 		watcher->Stop();
273 		watcher->PostMessage(B_QUIT_REQUESTED);
274 	}
275 	fVolumeWatcherList.MakeEmpty();
276 }
277 
278 
279 void
280 IndexServer::_SetupVolumeWatcher(VolumeWatcher* watcher)
281 {
282 	for (int i = 0; i < fAddOnList.CountItems(); i++) {
283 		IndexServerAddOn* addon = fAddOnList.ItemAt(i);
284 		FileAnalyser* analyser = _SetupFileAnalyser(addon, watcher->Volume());
285 		if (!analyser)
286 			continue;
287 		if (!watcher->AddAnalyser(analyser))
288 			delete analyser;
289 	}
290 }
291 
292 
293 FileAnalyser*
294 IndexServer::_SetupFileAnalyser(IndexServerAddOn* addon, const BVolume& volume)
295 {
296 	FileAnalyser* analyser = addon->CreateFileAnalyser(volume);
297 	if (!analyser)
298 		return NULL;
299 	AnalyserSettings* settings = new AnalyserSettings(analyser->Name(),
300 		analyser->Volume());
301 	BReference<AnalyserSettings> settingsRef(settings, true);
302 	if (!settings) {
303 		delete analyser;
304 		return NULL;
305 	}
306 	analyser->SetSettings(settings);
307 	return analyser;
308 }
309 
310 
311 void
312 IndexServer::_StartWatchingAddOns()
313 {
314 	AddHandler(&fAddOnMonitorHandler);
315 
316 	BMessage pulse(B_PULSE);
317 	fPulseRunner = new BMessageRunner(&fAddOnMonitorHandler, &pulse, 1000000LL);
318 		// the monitor handler needs a pulse to check if add-ons are ready
319 
320 	fAddOnMonitorHandler.AddAddOnDirectories("index_server");
321 }
322 
323 
324 IndexServerAddOn*
325 IndexServer::_FindAddon(const BString& name)
326 {
327 	for (int i = 0; i < fAddOnList.CountItems(); i++) {
328 		IndexServerAddOn* current = fAddOnList.ItemAt(i);
329 		if (current->Name() == name)
330 			return current;
331 	}
332 	return NULL;
333 }
334