storage;
#if ORTHANC_ENABLE_PLUGINS == 1
std::string databaseServerIdentifier;
{
OrthancConfiguration::ReaderLock lock;
databaseServerIdentifier = lock.GetConfiguration().GetDatabaseServerIdentifier();
}
OrthancPlugins plugins(databaseServerIdentifier);
plugins.SetCommandLineArguments(argc, argv);
LoadPlugins(plugins);
IDatabaseWrapper* database = NULL;
if (plugins.HasDatabaseBackend())
{
LOG(WARNING) << "Using a custom database from plugins";
database = &plugins.GetDatabaseBackend();
}
else
{
databasePtr.reset(CreateDatabaseWrapper());
database = databasePtr.get();
}
if (plugins.HasStorageArea())
{
LOG(WARNING) << "Using a custom storage area from plugins";
storage.reset(plugins.CreateStorageArea());
}
else
{
storage.reset(CreateStorageArea());
}
assert(database != NULL);
assert(storage.get() != NULL);
return ConfigureDatabase(*database, *storage, &plugins,
upgradeDatabase, loadJobsFromDatabase);
#elif ORTHANC_ENABLE_PLUGINS == 0
// The plugins are disabled
databasePtr.reset(CreateDatabaseWrapper());
storage.reset(CreateStorageArea());
assert(databasePtr.get() != NULL);
assert(storage.get() != NULL);
return ConfigureDatabase(*databasePtr, *storage, NULL,
upgradeDatabase, loadJobsFromDatabase);
#else
# error The macro ORTHANC_ENABLE_PLUGINS must be set to 0 or 1
#endif
}
static bool StartOrthanc(int argc,
char* argv[],
bool upgradeDatabase,
bool loadJobsFromDatabase)
{
return ConfigurePlugins(argc, argv, upgradeDatabase, loadJobsFromDatabase);
}
static bool SetCategoryVerbosity(const Verbosity verbosity,
const std::string& category)
{
Logging::LogCategory c;
if (LookupCategory(c, category))
{
SetCategoryVerbosity(c, verbosity);
return true;
}
else
{
return false;
}
}
static bool DisplayPerformanceWarning()
{
(void) DisplayPerformanceWarning; // Disable warning about unused function
LOG(WARNING) << "Performance warning: Non-release build, runtime debug assertions are turned on";
return true;
}
int main(int argc, char* argv[])
{
Logging::Initialize();
Logging::SetCurrentThreadName("MAIN");
SetGlobalVerbosity(Verbosity_Default);
bool upgradeDatabase = false;
bool loadJobsFromDatabase = true;
const char* configurationFile = NULL;
/**
* Parse the command-line options.
**/
for (int i = 1; i < argc; i++)
{
std::string argument(argv[i]);
if (argument.empty())
{
// Ignore empty arguments
}
else if (argument[0] != '-')
{
if (configurationFile != NULL)
{
LOG(ERROR) << "More than one configuration path were provided on the command line, aborting";
return -1;
}
else
{
// Use the first argument that does not start with a "-" as
// the configuration file
// TODO WHAT IS THE ENCODING?
configurationFile = argv[i];
}
}
else if (argument == "--errors")
{
PrintErrors(argv[0]);
return 0;
}
else if (argument == "--help")
{
PrintHelp(argv[0]);
return 0;
}
else if (argument == "--version")
{
PrintVersion(argv[0]);
return 0;
}
else if (argument == "--verbose")
{
SetGlobalVerbosity(Verbosity_Verbose);
}
else if (argument == "--logs-no-thread")
{
Logging::EnableThreadNames(false);
}
else if (argument == "--trace")
{
SetGlobalVerbosity(Verbosity_Trace);
}
else if (boost::starts_with(argument, "--verbose-") &&
SetCategoryVerbosity(Verbosity_Verbose, argument.substr(10)))
{
// New in Orthanc 1.8.1
}
else if (boost::starts_with(argument, "--trace-") &&
SetCategoryVerbosity(Verbosity_Trace, argument.substr(8)))
{
// New in Orthanc 1.8.1
}
else if (boost::starts_with(argument, "--logdir="))
{
// TODO WHAT IS THE ENCODING?
const std::string directory = argument.substr(9);
try
{
Logging::SetTargetFolder(directory);
}
catch (OrthancException&)
{
LOG(ERROR) << "The directory where to store the log files ("
<< directory << ") is inexistent, aborting.";
return -1;
}
}
else if (boost::starts_with(argument, "--logfile="))
{
// TODO WHAT IS THE ENCODING?
const std::string file = argument.substr(10);
try
{
Logging::SetTargetFile(file);
}
catch (OrthancException&)
{
LOG(ERROR) << "Cannot write to the specified log file ("
<< file << "), aborting.";
return -1;
}
}
else if (argument == "--upgrade")
{
upgradeDatabase = true;
}
else if (argument == "--no-jobs")
{
loadJobsFromDatabase = false;
}
else if (boost::starts_with(argument, "--config="))
{
// TODO WHAT IS THE ENCODING?
std::string configurationSample;
GetFileResource(configurationSample, ServerResources::CONFIGURATION_SAMPLE);
#if defined(_WIN32)
// Replace UNIX newlines with DOS newlines
boost::replace_all(configurationSample, "\n", "\r\n");
#endif
std::string target = argument.substr(9);
try
{
if (target == "-")
{
// New in 1.5.8: Print to stdout
std::cout << configurationSample;
}
else
{
SystemToolbox::WriteFile(configurationSample, target);
}
return 0;
}
catch (OrthancException&)
{
LOG(ERROR) << "Cannot write sample configuration as file \"" << target << "\"";
return -1;
}
}
else if (boost::starts_with(argument, "--openapi="))
{
std::string target = argument.substr(10);
try
{
Json::Value openapi;
{
SQLiteDatabaseWrapper inMemoryDatabase;
inMemoryDatabase.Open();
PluginStorageAreaAdapter inMemoryStorage(new MemoryStorageArea);
ServerContext context(inMemoryDatabase, inMemoryStorage, true /* unit testing */, 0 /* max completed jobs */, false /* readonly */, 1 /* DCMTK concurrent transcoders */);
OrthancRestApi restApi(context, false /* no Orthanc Explorer */);
restApi.GenerateOpenApiDocumentation(openapi);
context.Stop();
}
openapi["info"]["version"] = ORTHANC_VERSION;
openapi["info"]["title"] = "Orthanc API";
openapi["info"]["description"] =
"This is the full documentation of the [REST API](https://orthanc.uclouvain.be/book/users/rest.html) "
"of Orthanc.This reference is automatically generated from the source code of Orthanc. A "
"[shorter cheat sheet](https://orthanc.uclouvain.be/book/users/rest-cheatsheet.html) is part of "
"the Orthanc Book.
An earlier, manually crafted version from August 2019, is [still available]"
"(2019-08-orthanc-openapi.html), but is not up-to-date anymore ([source]"
"(https://groups.google.com/g/orthanc-users/c/NUiJTEICSl8/m/xKeqMrbqAAAJ)).";
Json::Value server = Json::objectValue;
server["url"] = "https://orthanc.uclouvain.be/demo/";
openapi["servers"].append(server);
std::string s;
Toolbox::WriteStyledJson(s, openapi);
if (target == "-")
{
std::cout << s; // Print to stdout
}
else
{
SystemToolbox::WriteFile(s, target);
}
return 0;
}
catch (OrthancException&)
{
LOG(ERROR) << "Cannot export OpenAPI documentation as file \"" << target << "\"";
return -1;
}
}
else if (boost::starts_with(argument, "--cheatsheet="))
{
std::string target = argument.substr(13);
try
{
std::string cheatsheet;
{
SQLiteDatabaseWrapper inMemoryDatabase;
inMemoryDatabase.Open();
PluginStorageAreaAdapter inMemoryStorage(new MemoryStorageArea);
ServerContext context(inMemoryDatabase, inMemoryStorage, true /* unit testing */, 0 /* max completed jobs */, false /* readonly */, 1 /* DCMTK concurrent transcoders */);
OrthancRestApi restApi(context, false /* no Orthanc Explorer */);
restApi.GenerateReStructuredTextCheatSheet(cheatsheet, "https://orthanc.uclouvain.be/api/index.html");
context.Stop();
}
if (target == "-")
{
std::cout << cheatsheet; // Print to stdout
}
else
{
SystemToolbox::WriteFile(cheatsheet, target);
}
return 0;
}
catch (OrthancException&)
{
LOG(ERROR) << "Cannot export REST cheat sheet as file \"" << target << "\"";
return -1;
}
}
else
{
LOG(WARNING) << "Option unsupported by the core of Orthanc: " << argument;
}
}
/**
* Launch Orthanc.
**/
{
std::string version(ORTHANC_VERSION);
if (std::string(ORTHANC_VERSION) == "mainline")
{
try
{
boost::filesystem::path exe(SystemToolbox::GetPathToExecutable());
std::time_t creation = boost::filesystem::last_write_time(exe);
boost::posix_time::ptime converted(boost::posix_time::from_time_t(creation));
version += " (" + boost::posix_time::to_iso_string(converted) + ")";
}
catch (...)
{
}
}
LOG(WARNING) << "Orthanc version: " << version;
assert(DisplayPerformanceWarning());
std::string s = "Architecture: ";
if (sizeof(void*) == 4)
{
s += "32-bit, ";
}
else if (sizeof(void*) == 8)
{
s += "64-bit, ";
}
else
{
s += "unsupported pointer size, ";
}
switch (Toolbox::DetectEndianness())
{
case Endianness_Little:
s += "little endian";
break;
case Endianness_Big:
s += "big endian";
break;
default:
s += "unsupported endianness";
break;
}
LOG(INFO) << s;
}
int status = 0;
try
{
for (;;)
{
OrthancInitialize(configurationFile);
bool restart = StartOrthanc(argc, argv, upgradeDatabase, loadJobsFromDatabase);
if (restart)
{
OrthancFinalize();
LOG(WARNING) << "Logging system is resetting";
Logging::Reset();
}
else
{
break;
}
}
}
catch (const OrthancException& e)
{
LOG(ERROR) << "Uncaught exception, stopping now: [" << e.What() << "] (code " << e.GetErrorCode() << ")";
#if defined(_WIN32)
if (e.GetErrorCode() >= ErrorCode_START_PLUGINS)
{
status = static_cast(ErrorCode_Plugin);
}
else
{
status = static_cast(e.GetErrorCode());
}
#else
status = -1;
#endif
}
catch (const std::exception& e)
{
LOG(ERROR) << "Uncaught exception, stopping now: [" << e.what() << "]";
status = -1;
}
catch (const std::string& s)
{
LOG(ERROR) << "Uncaught exception, stopping now: [" << s << "]";
status = -1;
}
catch (...)
{
LOG(ERROR) << "Native exception, stopping now. Check your plugins, if any.";
status = -1;
}
LOG(WARNING) << "Orthanc has stopped";
OrthancFinalize();
return status;
}