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