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