mirror of https://gitee.com/bigwinds/arangodb
added ScriptFeature
This commit is contained in:
parent
de67e378e9
commit
41b765ad76
|
@ -225,6 +225,7 @@ add_executable(${BIN_ARANGOD}
|
|||
RestServer/FrontendFeature.cpp
|
||||
RestServer/QueryRegistryFeature.cpp
|
||||
RestServer/RestServerFeature.cpp
|
||||
RestServer/ScriptFeature.cpp
|
||||
RestServer/ServerFeature.cpp
|
||||
RestServer/UpgradeFeature.cpp
|
||||
RestServer/VocbaseContext.cpp
|
||||
|
|
|
@ -42,7 +42,7 @@ ConsoleFeature::ConsoleFeature(application_features::ApplicationServer* server)
|
|||
}
|
||||
|
||||
void ConsoleFeature::start() {
|
||||
ServerFeature* server = ApplicationServer::getFeature<ServerFeature>("Server");
|
||||
auto server = ApplicationServer::getFeature<ServerFeature>("Server");
|
||||
|
||||
_operationMode = server->operationMode();
|
||||
|
||||
|
@ -50,8 +50,7 @@ void ConsoleFeature::start() {
|
|||
return;
|
||||
}
|
||||
|
||||
DatabaseFeature* database =
|
||||
ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
auto database = ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
|
||||
_consoleThread.reset(
|
||||
new ConsoleThread(ApplicationFeature::server(), database->vocbase()));
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "ScriptFeature.h"
|
||||
|
||||
#include "Basics/messages.h"
|
||||
#include "ProgramOptions/ProgramOptions.h"
|
||||
#include "ProgramOptions/Section.h"
|
||||
#include "RestServer/ConsoleThread.h"
|
||||
#include "RestServer/DatabaseFeature.h"
|
||||
#include "RestServer/ServerFeature.h"
|
||||
#include "V8/v8-conv.h"
|
||||
#include "V8/v8-globals.h"
|
||||
#include "V8/v8-utils.h"
|
||||
#include "V8Server/V8Context.h"
|
||||
#include "V8Server/V8DealerFeature.h"
|
||||
|
||||
using namespace arangodb;
|
||||
using namespace arangodb::application_features;
|
||||
using namespace arangodb::options;
|
||||
|
||||
ScriptFeature::ScriptFeature(application_features::ApplicationServer* server, int* result)
|
||||
: ApplicationFeature(server, "Script"),
|
||||
_result(result) {
|
||||
startsAfter("Nonce");
|
||||
startsAfter("Server");
|
||||
startsAfter("RestServer");
|
||||
}
|
||||
|
||||
void ScriptFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
|
||||
options->addSection("javascript", "Configure the Javascript engine");
|
||||
|
||||
options->addOption("--javascript.script-parameter", "script parameter",
|
||||
new VectorParameter<StringParameter>(&_scriptParameters));
|
||||
}
|
||||
|
||||
void ScriptFeature::start() {
|
||||
auto server = ApplicationServer::getFeature<ServerFeature>("Server");
|
||||
auto operationMode = server->operationMode();
|
||||
|
||||
if (operationMode != OperationMode::MODE_SCRIPT) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_TOPIC(TRACE, Logger::STARTUP) << "server about to run scripts";
|
||||
*_result = runScript(server->scripts());
|
||||
}
|
||||
|
||||
int ScriptFeature::runScript(std::vector<std::string> const& scripts) {
|
||||
bool ok = false;
|
||||
|
||||
auto database = ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
V8Context* context =
|
||||
V8DealerFeature::DEALER->enterContext(database->vocbase(), true);
|
||||
auto isolate = context->_isolate;
|
||||
|
||||
{
|
||||
v8::HandleScope globalScope(isolate);
|
||||
|
||||
auto localContext = v8::Local<v8::Context>::New(isolate, context->_context);
|
||||
localContext->Enter();
|
||||
{
|
||||
v8::Context::Scope contextScope(localContext);
|
||||
for (auto script : scripts) {
|
||||
LOG(TRACE) << "executing script '" << script << "'";
|
||||
bool r = TRI_ExecuteGlobalJavaScriptFile(isolate, script.c_str(), true);
|
||||
|
||||
if (!r) {
|
||||
LOG(FATAL) << "cannot load script '" << script << "', giving up";
|
||||
FATAL_ERROR_EXIT();
|
||||
}
|
||||
}
|
||||
|
||||
v8::TryCatch tryCatch;
|
||||
// run the garbage collection for at most 30 seconds
|
||||
TRI_RunGarbageCollectionV8(isolate, 30.0);
|
||||
|
||||
// parameter array
|
||||
v8::Handle<v8::Array> params = v8::Array::New(isolate);
|
||||
|
||||
params->Set(0, TRI_V8_STD_STRING(scripts[scripts.size() - 1]));
|
||||
|
||||
for (size_t i = 0; i < _scriptParameters.size(); ++i) {
|
||||
params->Set((uint32_t)(i + 1), TRI_V8_STD_STRING(_scriptParameters[i]));
|
||||
}
|
||||
|
||||
// call main
|
||||
v8::Handle<v8::String> mainFuncName = TRI_V8_ASCII_STRING("main");
|
||||
v8::Handle<v8::Function> main = v8::Handle<v8::Function>::Cast(
|
||||
localContext->Global()->Get(mainFuncName));
|
||||
|
||||
if (main.IsEmpty() || main->IsUndefined()) {
|
||||
LOG(FATAL) << "no main function defined, giving up";
|
||||
FATAL_ERROR_EXIT();
|
||||
} else {
|
||||
v8::Handle<v8::Value> args[] = {params};
|
||||
|
||||
try {
|
||||
v8::Handle<v8::Value> result = main->Call(main, 1, args);
|
||||
|
||||
if (tryCatch.HasCaught()) {
|
||||
if (tryCatch.CanContinue()) {
|
||||
TRI_LogV8Exception(isolate, &tryCatch);
|
||||
} else {
|
||||
// will stop, so need for v8g->_canceled = true;
|
||||
TRI_ASSERT(!ok);
|
||||
}
|
||||
} else {
|
||||
ok = TRI_ObjectToDouble(result) == 0;
|
||||
}
|
||||
} catch (arangodb::basics::Exception const& ex) {
|
||||
LOG(ERR) << "caught exception " << TRI_errno_string(ex.code()) << ": "
|
||||
<< ex.what();
|
||||
ok = false;
|
||||
} catch (std::bad_alloc const&) {
|
||||
LOG(ERR) << "caught exception "
|
||||
<< TRI_errno_string(TRI_ERROR_OUT_OF_MEMORY);
|
||||
ok = false;
|
||||
} catch (...) {
|
||||
LOG(ERR) << "caught unknown exception";
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
localContext->Exit();
|
||||
}
|
||||
|
||||
V8DealerFeature::DEALER->exitContext(context);
|
||||
|
||||
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef APPLICATION_FEATURES_SCRIPT_FEATURE_H
|
||||
#define APPLICATION_FEATURES_SCRIPT_FEATURE_H 1
|
||||
|
||||
#include "ApplicationFeatures/ApplicationFeature.h"
|
||||
|
||||
#include "Rest/OperationMode.h"
|
||||
|
||||
namespace arangodb {
|
||||
class ScriptThread;
|
||||
|
||||
class ScriptFeature final : public application_features::ApplicationFeature {
|
||||
public:
|
||||
explicit ScriptFeature(application_features::ApplicationServer*, int* result);
|
||||
|
||||
public:
|
||||
void collectOptions(std::shared_ptr<options::ProgramOptions>) override final;
|
||||
void start() override final;
|
||||
|
||||
private:
|
||||
std::vector<std::string> _scriptParameters;
|
||||
|
||||
private:
|
||||
int runScript(std::vector<std::string> const& scripts);
|
||||
|
||||
private:
|
||||
int* _result;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -49,8 +49,6 @@ using namespace arangodb::rest;
|
|||
ServerFeature::ServerFeature(application_features::ApplicationServer* server,
|
||||
int* res)
|
||||
: ApplicationFeature(server, "Server"),
|
||||
_console(false),
|
||||
_restServer(true),
|
||||
_result(res),
|
||||
_operationMode(OperationMode::MODE_SERVER) {
|
||||
setOptional(true);
|
||||
|
@ -91,8 +89,6 @@ void ServerFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
|
|||
options->addOption("--javascript.script", "run scripts and exit",
|
||||
new VectorParameter<StringParameter>(&_scripts));
|
||||
|
||||
options->addOption("--javascript.script-parameter", "script parameter",
|
||||
new VectorParameter<StringParameter>(&_scriptParameters));
|
||||
}
|
||||
|
||||
void ServerFeature::validateOptions(std::shared_ptr<ProgramOptions>) {
|
||||
|
@ -186,8 +182,6 @@ void ServerFeature::start() {
|
|||
break;
|
||||
|
||||
case OperationMode::MODE_SCRIPT:
|
||||
LOG_TOPIC(TRACE, Logger::STARTUP) << "server about to run scripts";
|
||||
*_result = runScript();
|
||||
break;
|
||||
|
||||
case OperationMode::MODE_CONSOLE:
|
||||
|
@ -291,90 +285,3 @@ int ServerFeature::runUnitTests() {
|
|||
|
||||
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int ServerFeature::runScript() {
|
||||
bool ok = false;
|
||||
|
||||
DatabaseFeature* database =
|
||||
ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
V8Context* context =
|
||||
V8DealerFeature::DEALER->enterContext(database->vocbase(), true);
|
||||
|
||||
auto isolate = context->_isolate;
|
||||
|
||||
{
|
||||
v8::HandleScope globalScope(isolate);
|
||||
|
||||
auto localContext = v8::Local<v8::Context>::New(isolate, context->_context);
|
||||
localContext->Enter();
|
||||
{
|
||||
v8::Context::Scope contextScope(localContext);
|
||||
for (auto script : _scripts) {
|
||||
LOG(TRACE) << "executing script '" << script << "'";
|
||||
bool r = TRI_ExecuteGlobalJavaScriptFile(isolate, script.c_str(), true);
|
||||
|
||||
if (!r) {
|
||||
LOG(FATAL) << "cannot load script '" << script << "', giving up";
|
||||
FATAL_ERROR_EXIT();
|
||||
}
|
||||
}
|
||||
|
||||
v8::TryCatch tryCatch;
|
||||
// run the garbage collection for at most 30 seconds
|
||||
TRI_RunGarbageCollectionV8(isolate, 30.0);
|
||||
|
||||
// parameter array
|
||||
v8::Handle<v8::Array> params = v8::Array::New(isolate);
|
||||
|
||||
params->Set(0, TRI_V8_STD_STRING(_scripts[_scripts.size() - 1]));
|
||||
|
||||
for (size_t i = 0; i < _scriptParameters.size(); ++i) {
|
||||
params->Set((uint32_t)(i + 1), TRI_V8_STD_STRING(_scriptParameters[i]));
|
||||
}
|
||||
|
||||
// call main
|
||||
v8::Handle<v8::String> mainFuncName = TRI_V8_ASCII_STRING("main");
|
||||
v8::Handle<v8::Function> main = v8::Handle<v8::Function>::Cast(
|
||||
localContext->Global()->Get(mainFuncName));
|
||||
|
||||
if (main.IsEmpty() || main->IsUndefined()) {
|
||||
LOG(FATAL) << "no main function defined, giving up";
|
||||
FATAL_ERROR_EXIT();
|
||||
} else {
|
||||
v8::Handle<v8::Value> args[] = {params};
|
||||
|
||||
try {
|
||||
v8::Handle<v8::Value> result = main->Call(main, 1, args);
|
||||
|
||||
if (tryCatch.HasCaught()) {
|
||||
if (tryCatch.CanContinue()) {
|
||||
TRI_LogV8Exception(isolate, &tryCatch);
|
||||
} else {
|
||||
// will stop, so need for v8g->_canceled = true;
|
||||
TRI_ASSERT(!ok);
|
||||
}
|
||||
} else {
|
||||
ok = TRI_ObjectToDouble(result) == 0;
|
||||
}
|
||||
} catch (arangodb::basics::Exception const& ex) {
|
||||
LOG(ERR) << "caught exception " << TRI_errno_string(ex.code()) << ": "
|
||||
<< ex.what();
|
||||
ok = false;
|
||||
} catch (std::bad_alloc const&) {
|
||||
LOG(ERR) << "caught exception "
|
||||
<< TRI_errno_string(TRI_ERROR_OUT_OF_MEMORY);
|
||||
ok = false;
|
||||
} catch (...) {
|
||||
LOG(ERR) << "caught unknown exception";
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
localContext->Exit();
|
||||
}
|
||||
|
||||
V8DealerFeature::DEALER->exitContext(context);
|
||||
|
||||
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,10 @@ class AsyncJobManager;
|
|||
|
||||
class ServerFeature final : public application_features::ApplicationFeature {
|
||||
public:
|
||||
ServerFeature(application_features::ApplicationServer* server, int*);
|
||||
static std::string operationModeString(OperationMode mode);
|
||||
|
||||
public:
|
||||
ServerFeature(application_features::ApplicationServer*, int* result);
|
||||
|
||||
public:
|
||||
void collectOptions(std::shared_ptr<options::ProgramOptions>) override final;
|
||||
|
@ -45,24 +48,22 @@ class ServerFeature final : public application_features::ApplicationFeature {
|
|||
|
||||
public:
|
||||
OperationMode operationMode() const { return _operationMode; }
|
||||
|
||||
|
||||
std::string operationModeString() const {
|
||||
return operationModeString(operationMode());
|
||||
}
|
||||
|
||||
static std::string operationModeString(OperationMode mode);
|
||||
std::vector<std::string> const& scripts() const { return _scripts; }
|
||||
|
||||
private:
|
||||
bool _console;
|
||||
bool _restServer;
|
||||
bool _console = false;
|
||||
bool _restServer = true;
|
||||
std::vector<std::string> _unitTests;
|
||||
std::vector<std::string> _scripts;
|
||||
std::vector<std::string> _scriptParameters;
|
||||
|
||||
private:
|
||||
void waitForHeartbeat();
|
||||
int runUnitTests();
|
||||
int runScript();
|
||||
|
||||
private:
|
||||
int* _result;
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include "RestServer/FrontendFeature.h"
|
||||
#include "RestServer/QueryRegistryFeature.h"
|
||||
#include "RestServer/RestServerFeature.h"
|
||||
#include "RestServer/ScriptFeature.h"
|
||||
#include "RestServer/ServerFeature.h"
|
||||
#include "RestServer/UpgradeFeature.h"
|
||||
#include "Scheduler/SchedulerFeature.h"
|
||||
|
@ -69,7 +70,7 @@ using namespace arangodb::wal;
|
|||
/// @brief Hooks for OS-Specific functions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//YYY #warning TODO
|
||||
// YYY #warning TODO
|
||||
#if 0
|
||||
#ifdef _WIN32
|
||||
extern bool TRI_ParseMoreArgs(int argc, char* argv[]);
|
||||
|
@ -98,8 +99,11 @@ int main(int argc, char* argv[]) {
|
|||
application_features::ApplicationServer server(options);
|
||||
|
||||
std::vector<std::string> nonServerFeatures = {
|
||||
"Action", "Affinity", "Agency", "Cluster", "Daemon", "Dispatcher", "Endpoint", "FoxxQueues",
|
||||
"LoggerBufferFeature", "RestServer", "Server", "Scheduler", "Ssl", "Statistics", "Supervisor"};
|
||||
"Action", "Affinity", "Agency",
|
||||
"Cluster", "Daemon", "Dispatcher",
|
||||
"Endpoint", "FoxxQueues", "LoggerBufferFeature",
|
||||
"RestServer", "Server", "Scheduler",
|
||||
"Ssl", "Statistics", "Supervisor"};
|
||||
|
||||
int ret = EXIT_FAILURE;
|
||||
|
||||
|
@ -127,6 +131,7 @@ int main(int argc, char* argv[]) {
|
|||
server.addFeature(new RandomFeature(&server));
|
||||
server.addFeature(new RestServerFeature(&server, "arangodb"));
|
||||
server.addFeature(new SchedulerFeature(&server));
|
||||
server.addFeature(new ScriptFeature(&server, &ret));
|
||||
server.addFeature(new ServerFeature(&server, &ret));
|
||||
server.addFeature(new ShutdownFeature(&server, "Server"));
|
||||
server.addFeature(new SslFeature(&server));
|
||||
|
@ -150,20 +155,23 @@ int main(int argc, char* argv[]) {
|
|||
try {
|
||||
server.run(argc, argv);
|
||||
} catch (arangodb::basics::Exception const& ex) {
|
||||
LOG(ERR) << "arangod terminated because of an unhandled exception: " << ex.what();
|
||||
LOG(ERR) << "arangod terminated because of an unhandled exception: "
|
||||
<< ex.what();
|
||||
ret = EXIT_FAILURE;
|
||||
} catch (std::exception const& ex) {
|
||||
LOG(ERR) << "arangod terminated because of an unhandled exception: " << ex.what();
|
||||
LOG(ERR) << "arangod terminated because of an unhandled exception: "
|
||||
<< ex.what();
|
||||
ret = EXIT_FAILURE;
|
||||
} catch (...) {
|
||||
LOG(ERR) << "arangod terminated because of an unhandled exception of unknown type";
|
||||
LOG(ERR) << "arangod terminated because of an unhandled exception of "
|
||||
"unknown type";
|
||||
ret = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return context.exit(ret);
|
||||
}
|
||||
|
||||
//YYY #warning TODO
|
||||
// YYY #warning TODO
|
||||
#if 0
|
||||
|
||||
// windows only
|
||||
|
|
|
@ -207,8 +207,8 @@ target_link_libraries(${BIN_ARANGOSH}
|
|||
${LIB_ARANGO_V8}
|
||||
${LIB_ARANGO}
|
||||
${LINENOISE_LIBS}
|
||||
${MSVC_LIBS}
|
||||
${V8_LIBS}
|
||||
${MSVC_LIBS}
|
||||
${SYSTEM_LIBRARIES}
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in New Issue