333 lines
6.7 KiB
C++
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;
|
|
}
|