haiku/src/servers/index/IndexServer.cpp

333 lines
6.7 KiB
C++

/*
* Copyright 2010-2013 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* John Scipione, jscipione@gmail.com
* Clemens Zeidler, haiku@clemens-zeidler.de
*/
#include "IndexServer.h"
#include <Path.h>
#include <String.h>
VolumeObserverHandler::VolumeObserverHandler(IndexServer* indexServer)
:
fIndexServer(indexServer)
{
}
void
VolumeObserverHandler::MessageReceived(BMessage* message)
{
if (message->what != B_NODE_MONITOR)
return;
dev_t device;
int32 opcode;
message->FindInt32("opcode", &opcode) ;
switch (opcode) {
case B_DEVICE_MOUNTED :
message->FindInt32("new device", &device);
fIndexServer->AddVolume(BVolume(device));
break ;
case B_DEVICE_UNMOUNTED :
message->FindInt32("device", &device);
fIndexServer->RemoveVolume(BVolume(device));
break ;
}
}
AnalyserMonitorHandler::AnalyserMonitorHandler(IndexServer* indexServer)
:
fIndexServer(indexServer)
{
}
void
AnalyserMonitorHandler::AddOnEnabled(const add_on_entry_info* entryInfo)
{
entry_ref ref;
make_entry_ref(entryInfo->dir_nref.device, entryInfo->dir_nref.node,
entryInfo->name, &ref);
fIndexServer->RegisterAddOn(ref);
};
void
AnalyserMonitorHandler::AddOnDisabled(const add_on_entry_info* entryInfo)
{
entry_ref ref;
make_entry_ref(entryInfo->dir_nref.device, entryInfo->dir_nref.node,
entryInfo->name, &ref);
fIndexServer->UnregisterAddOn(ref);
};
IndexServer::IndexServer()
:
BApplication("application/x-vnd.Haiku-index_server"),
fVolumeObserverHandler(this),
fAddOnMonitorHandler(this),
fPulseRunner(NULL)
{
AddHandler(&fVolumeObserverHandler);
AddHandler(&fAddOnMonitorHandler);
}
IndexServer::~IndexServer()
{
for (int i = 0; i < fAddOnList.CountItems(); i++) {
IndexServerAddOn* addon = fAddOnList.ItemAt(i);
for (int i = 0; i < fVolumeWatcherList.CountItems(); i++)
fVolumeWatcherList.ItemAt(i)->RemoveAnalyser(addon->Name());
image_id image = addon->ImageId();
delete addon;
unload_add_on(image);
}
_StopWatchingVolumes();
delete fPulseRunner;
RemoveHandler(&fVolumeObserverHandler);
RemoveHandler(&fAddOnMonitorHandler);
}
void
IndexServer::ReadyToRun()
{
_StartWatchingAddOns();
_StartWatchingVolumes();
}
void
IndexServer::MessageReceived(BMessage *message)
{
BApplication::MessageReceived(message);
}
bool
IndexServer::QuitRequested()
{
_StopWatchingVolumes();
return BApplication::QuitRequested();
}
void
IndexServer::AddVolume(const BVolume& volume)
{
// ignore volumes like / or /dev
if (volume.Capacity() == 0)
return;
// check if volume is already in our list
for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
VolumeWatcher* current = fVolumeWatcherList.ItemAt(i);
if (current->Volume() == volume)
return;
}
char name[256];
volume.GetName(name);
STRACE("IndexServer::AddVolume %s\n", name);
VolumeWatcher* watcher = new VolumeWatcher(volume);
/* if (!watcher->Enabled()) {
delete watcher;
return;
}*/
fVolumeWatcherList.AddItem(watcher);
_SetupVolumeWatcher(watcher);
watcher->StartWatching();
}
void
IndexServer::RemoveVolume(const BVolume& volume)
{
VolumeWatcher* watcher = NULL;
for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
VolumeWatcher* current = fVolumeWatcherList.ItemAt(i);
if (current->Volume() == volume) {
watcher = current;
break;
}
}
if (!watcher)
return;
watcher->Stop();
fVolumeWatcherList.RemoveItem(watcher);
watcher->PostMessage(B_QUIT_REQUESTED);
}
void
IndexServer::RegisterAddOn(entry_ref ref)
{
STRACE("RegisterAddOn %s\n", ref.name);
BPath path(&ref);
image_id image = load_add_on(path.Path());
if (image < 0)
return;
create_index_server_addon* createFunc;
// Get the instantiation function
status_t status = get_image_symbol(image, "instantiate_index_server_addon",
B_SYMBOL_TYPE_TEXT, (void**)&createFunc);
if (status != B_OK) {
unload_add_on(image);
return;
}
IndexServerAddOn* addon = createFunc(image, ref.name);
if (!addon) {
unload_add_on(image);
return;
}
if (!fAddOnList.AddItem(addon)) {
unload_add_on(image);
return;
}
for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
VolumeWatcher* watcher = fVolumeWatcherList.ItemAt(i);
FileAnalyser* analyser = _SetupFileAnalyser(addon, watcher->Volume());
if (!analyser)
continue;
if (!watcher->AddAnalyser(analyser))
delete analyser;
}
}
void
IndexServer::UnregisterAddOn(entry_ref ref)
{
IndexServerAddOn* addon = _FindAddon(ref.name);
if (!addon)
return;
for (int i = 0; i < fVolumeWatcherList.CountItems(); i++)
fVolumeWatcherList.ItemAt(i)->RemoveAnalyser(addon->Name());
fAddOnList.RemoveItem(addon);
unload_add_on(addon->ImageId());
delete addon;
}
FileAnalyser*
IndexServer::CreateFileAnalyser(const BString& name, const BVolume& volume)
{
Lock();
IndexServerAddOn* addon = _FindAddon(name);
if (!addon) {
Unlock();
return NULL;
}
FileAnalyser* analyser = addon->CreateFileAnalyser(volume);
Unlock();
return analyser;
}
void
IndexServer::_StartWatchingVolumes()
{
BVolume volume;
while (fVolumeRoster.GetNextVolume(&volume) != B_BAD_VALUE)
AddVolume(volume);
fVolumeRoster.StartWatching(this);
}
void
IndexServer::_StopWatchingVolumes()
{
STRACE("_StopWatchingVolumes\n");
for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
VolumeWatcher* watcher = fVolumeWatcherList.ItemAt(i);
watcher->Stop();
watcher->PostMessage(B_QUIT_REQUESTED);
}
fVolumeWatcherList.MakeEmpty();
}
void
IndexServer::_SetupVolumeWatcher(VolumeWatcher* watcher)
{
for (int i = 0; i < fAddOnList.CountItems(); i++) {
IndexServerAddOn* addon = fAddOnList.ItemAt(i);
FileAnalyser* analyser = _SetupFileAnalyser(addon, watcher->Volume());
if (!analyser)
continue;
if (!watcher->AddAnalyser(analyser))
delete analyser;
}
}
FileAnalyser*
IndexServer::_SetupFileAnalyser(IndexServerAddOn* addon, const BVolume& volume)
{
FileAnalyser* analyser = addon->CreateFileAnalyser(volume);
if (!analyser)
return NULL;
AnalyserSettings* settings = new AnalyserSettings(analyser->Name(),
analyser->Volume());
BReference<AnalyserSettings> settingsRef(settings, true);
if (!settings) {
delete analyser;
return NULL;
}
analyser->SetSettings(settings);
return analyser;
}
void
IndexServer::_StartWatchingAddOns()
{
AddHandler(&fAddOnMonitorHandler);
BMessage pulse(B_PULSE);
fPulseRunner = new BMessageRunner(&fAddOnMonitorHandler, &pulse, 1000000LL);
// the monitor handler needs a pulse to check if add-ons are ready
fAddOnMonitorHandler.AddAddOnDirectories("index_server");
}
IndexServerAddOn*
IndexServer::_FindAddon(const BString& name)
{
for (int i = 0; i < fAddOnList.CountItems(); i++) {
IndexServerAddOn* current = fAddOnList.ItemAt(i);
if (current->Name() == name)
return current;
}
return NULL;
}