#4416 First implementation of gRPC-based Python interface

First implementation with Asynchronous gRPC server, a few services and some client python code.
This commit is contained in:
Gaute Lindkvist 2019-05-20 13:21:02 +02:00 committed by GitHub
parent 7df5ce9a92
commit 922386c673
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 2894 additions and 27 deletions

View File

@ -27,4 +27,8 @@
#define PRODUCTVER "@PRODUCTVER@"
#define STRPRODUCTVER "@STRPRODUCTVER@"
#define RESINSIGHT_MAJOR_VERSION @RESINSIGHT_MAJOR_VERSION@
#define RESINSIGHT_MINOR_VERSION @RESINSIGHT_MINOR_VERSION@
#define RESINSIGHT_PATCH_VERSION @RESINSIGHT_PATCH_VERSION@
#define RESINSIGHT_OCTAVE_VERSION "@OCTAVE_VERSION_STRING@"

View File

@ -0,0 +1,21 @@
#
# Copyright (C) 2019- Equinor ASA
#
# ResInsight is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.
#
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
# for more details.
#
# Python version of RiaVersionInfo.h
# Just sets version constants
RESINSIGHT_MAJOR_VERSION = "@RESINSIGHT_MAJOR_VERSION@"
RESINSIGHT_MINOR_VERSION = "@RESINSIGHT_MINOR_VERSION@"
RESINSIGHT_PATCH_VERSION = "@RESINSIGHT_PATCH_VERSION@"

View File

@ -1292,6 +1292,36 @@ cvf::Font* RiaApplication::defaultWellLabelFont()
return m_defaultWellLabelFont.p();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RiaApplication::initializeGrpcServer(const cvf::ProgramOptions& progOpt)
{
#ifdef ENABLE_GRPC
if (!m_preferences->enableGrpcServer()) return false;
int defaultPortNumber = m_preferences->defaultGrpcPortNumber();
bool fixedPort = false;
if (cvf::Option o = progOpt.option("grpcserver"))
{
if (o.valueCount() == 1)
{
defaultPortNumber = o.value(0).toInt(defaultPortNumber);
fixedPort = true;
}
}
int portNumber = defaultPortNumber;
if (!fixedPort)
{
portNumber = RiaGrpcServer::findAvailablePortNumber(defaultPortNumber);
}
m_grpcServer.reset(new RiaGrpcServer(portNumber));
return true;
#else
return false;
#endif
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -20,6 +20,9 @@
#pragma once
#include "RiaDefines.h"
#ifdef ENABLE_GRPC
#include "RiaGrpcServer.h"
#endif
#include "cafPdmField.h"
#include "cafPdmObject.h"
@ -93,7 +96,7 @@ public:
EXIT_COMPLETED,
EXIT_WITH_ERROR
};
public:
static RiaApplication* instance();
RiaApplication();
@ -171,6 +174,8 @@ public:
cvf::Font* defaultAnnotationFont();
cvf::Font* defaultWellLabelFont();
bool initializeGrpcServer(const cvf::ProgramOptions& progOpt);
// Public implementation specific overrides
virtual void initialize();
virtual ApplicationStatus handleArguments(cvf::ProgramOptions* progOpt) = 0;
@ -178,8 +183,7 @@ public:
virtual void addToRecentFiles(const QString& fileName) {}
virtual void showInformationMessage(const QString& infoText) = 0;
virtual void showErrorMessage(const QString& errMsg) = 0;
virtual void cleanupBeforeProgramExit() {}
virtual void launchGrpcServer() = 0;
protected:
// Protected implementation specific overrides
virtual void invokeProcessEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents) = 0;
@ -203,11 +207,14 @@ protected:
RiaSocketServer* m_socketServer;
caf::UiProcess* m_workerProcess;
#ifdef ENABLE_GRPC
std::unique_ptr<RiaGrpcServer> m_grpcServer;
#endif
// Execute for all settings
std::list<int> m_currentCaseIds;
QString m_currentProgram;
QStringList m_currentArguments;
RiaPreferences* m_preferences;
std::map<QString, QString> m_fileDialogDefaultDirectories;

View File

@ -339,6 +339,16 @@ void RiaConsoleApplication::showErrorMessage(const QString& errMsg)
RiaLogging::error(errMsg);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaConsoleApplication::launchGrpcServer()
{
#ifdef ENABLE_GRPC
m_grpcServer->run();
#endif
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -41,7 +41,7 @@ public:
ApplicationStatus handleArguments(cvf::ProgramOptions* progOpt) override;
void showInformationMessage(const QString& text) override;
void showErrorMessage(const QString& errMsg) override;
void launchGrpcServer() override;
protected:
// Protected implementation specific overrides
void invokeProcessEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents) override;

View File

@ -170,6 +170,15 @@ namespace RiaDefines
ImportFileType obtainFileTypeFromFileName(const QString& fileName);
QString defaultDirectoryLabel(ImportFileType fileTypes);
enum CaseType
{
ECLIPSE_RESULT_CASE = 1,
ECLIPSE_INPUT_CASE = 2,
ECLIPSE_STAT_CASE = 3,
ECLIPSE_SOURCE_CASE = 4,
GEOMECH_ODB_CASE = 5
};
enum FontSettingType
{
SCENE_FONT,

View File

@ -178,13 +178,11 @@ RiaGuiApplication::RiaGuiApplication(int& argc, char** argv)
, m_mainWindow(nullptr)
, m_mainPlotWindow(nullptr)
{
// For idle processing
// m_idleTimerStarted = false;
installEventFilter(this);
setWindowIcon(QIcon(":/AppLogo48x48.png"));
m_recentFileActionProvider = std::unique_ptr<RiuRecentFileActionProvider>(new RiuRecentFileActionProvider);
connect(this, SIGNAL(aboutToQuit()), this, SLOT(onProgramExit()));
}
//--------------------------------------------------------------------------------------------------
@ -571,8 +569,8 @@ void RiaGuiApplication::initialize()
RiaLogging::setLoggerInstance(new RiuMessagePanelLogger(m_mainWindow->messagePanel()));
RiaLogging::loggerInstance()->setLevel(RI_LL_DEBUG);
m_socketServer = new RiaSocketServer(this);
}
//--------------------------------------------------------------------------------------------------
@ -1231,6 +1229,19 @@ void RiaGuiApplication::showErrorMessage(const QString& errMsg)
errDialog.showMessage(errMsg);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGuiApplication::launchGrpcServer()
{
#ifdef ENABLE_GRPC
m_grpcServer->runInThread();
m_idleTimer = new QTimer(this);
connect(m_idleTimer, SIGNAL(timeout()), this, SLOT(runIdleProcessing()));
m_idleTimer->start(0);
#endif
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -1367,10 +1378,14 @@ void RiaGuiApplication::onProjectClosed()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGuiApplication::cleanupBeforeProgramExit()
void RiaGuiApplication::onProgramExit()
{
closeAllWindows();
invokeProcessEvents();
#ifdef ENABLE_GRPC
if (m_grpcServer)
{
m_grpcServer->quit();
}
#endif
}
//--------------------------------------------------------------------------------------------------
@ -1575,6 +1590,27 @@ void RiaGuiApplication::applyGuiPreferences(const RiaPreferences* oldPreferences
caf::PdmUiItem::enableExtraDebugText(m_preferences->appendFieldKeywordToToolTipText());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGuiApplication::updateGrpcServer()
{
#ifdef ENABLE_GRPC
bool isGrpcRunning = m_grpcServer != nullptr && m_grpcServer->isRunning();
bool shouldItBeRunning = m_preferences->enableGrpcServer();
if (isGrpcRunning && !shouldItBeRunning)
{
m_grpcServer->quit();
}
else if (!isGrpcRunning && shouldItBeRunning)
{
int portNumber = RiaGrpcServer::findAvailablePortNumber(m_preferences->defaultGrpcPortNumber());
m_grpcServer.reset(new RiaGrpcServer(portNumber));
m_grpcServer->runInThread();
}
#endif
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -1637,6 +1673,19 @@ void RiaGuiApplication::slotWorkerProcessFinished(int exitCode, QProcess::ExitSt
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGuiApplication::runIdleProcessing()
{
#ifdef ENABLE_GRPC
if (!caf::ProgressInfoStatic::isRunning())
{
m_grpcServer->processOneRequest();
}
#endif
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -28,8 +28,10 @@
#include <QApplication>
#include <QMutex>
#include <QPointer>
#include <QProcess>
#include <QString>
#include <QTimer>
#include <iostream>
#include <memory>
@ -121,6 +123,7 @@ public:
static void clearAllSelections();
void applyGuiPreferences(const RiaPreferences* oldPreferences = nullptr);
void updateGrpcServer();
// Public RiaApplication overrides
void initialize() override;
@ -129,7 +132,7 @@ public:
void addToRecentFiles(const QString& fileName) override;
void showInformationMessage(const QString& text) override;
void showErrorMessage(const QString& errMsg) override;
void cleanupBeforeProgramExit() override;
void launchGrpcServer() override;
protected:
// Protected RiaApplication overrides
void invokeProcessEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents) override;
@ -142,7 +145,7 @@ protected:
void startMonitoringWorkProgress(caf::UiProcess* uiProcess) override;
void stopMonitoringWorkProgress() override;
private:
private:
void setWindowCaptionFromAppState();
void createMainWindow();
@ -159,11 +162,16 @@ private:
private slots:
void slotWorkerProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
void runIdleProcessing();
void onProgramExit();
private:
RiuMainWindow* m_mainWindow;
RiuPlotMainWindow* m_mainPlotWindow;
#ifdef ENABLE_GRPC
QPointer<QTimer> m_idleTimer;
#endif
std::unique_ptr<RiuRecentFileActionProvider> m_recentFileActionProvider;
std::unique_ptr<RiuMdiMaximizeWindowGuard> m_maximizeWindowGuard;

View File

@ -41,11 +41,11 @@ int main(int argc, char *argv[])
RiaLogging::loggerInstance()->setLevel(RI_LL_DEBUG);
std::unique_ptr<RiaApplication> app (createApplication(argc, argv));
app->initialize();
cvf::ProgramOptions progOpt;
bool result = RiaArgumentParser::parseArguments(&progOpt);
bool result = RiaArgumentParser::parseArguments(&progOpt);
app->initialize();
if (!result)
{
@ -60,7 +60,6 @@ int main(int argc, char *argv[])
app->showErrorMessage(RiaApplication::commandLineParameterHelp() +
cvfqt::Utils::toQString(usageText) +
unknownOptionsText.join("\n"));
app->cleanupBeforeProgramExit();
if (dynamic_cast<RiaGuiApplication*>(app.get()) == nullptr)
{
return 1;
@ -84,6 +83,10 @@ int main(int argc, char *argv[])
int exitCode = 0;
try
{
if (app->initializeGrpcServer(progOpt))
{
app->launchGrpcServer();
}
exitCode = QCoreApplication::instance()->exec();
}
catch (std::exception& exep )

View File

@ -51,6 +51,9 @@ RiaPreferences::RiaPreferences(void)
{
CAF_PDM_InitField(&navigationPolicy, "navigationPolicy", caf::AppEnum<RiaGuiApplication::RINavigationPolicy>(RiaGuiApplication::NAVIGATION_POLICY_RMS), "Navigation Mode", "", "", "");
CAF_PDM_InitField(&enableGrpcServer, "enableGrpcServer", true, "Enable gRPC script server", "", "Remote Procedure Call Scripting Engine", "");
CAF_PDM_InitField(&defaultGrpcPortNumber, "defaultGrpcPort", 50051, "Default gRPC port", "", "", "");
CAF_PDM_InitFieldNoDefault(&scriptDirectories, "scriptDirectory", "Shared Script Folder(s)", "", "", "");
scriptDirectories.uiCapability()->setUiEditorTypeName(caf::PdmUiFilePathEditor::uiEditorTypeName());
@ -129,7 +132,7 @@ RiaPreferences::RiaPreferences(void)
m_tabNames << "General";
m_tabNames << "Eclipse";
m_tabNames << "Octave";
m_tabNames << "Scripting";
if (RiaApplication::enableDevelopmentFeatures())
{
m_tabNames << "System";
@ -245,6 +248,12 @@ void RiaPreferences::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering&
}
else if (uiConfigName == m_tabNames[2])
{
#ifdef ENABLE_GRPC
caf::PdmUiGroup* grpcGroup = uiOrdering.addNewGroup("gRPC Server");
grpcGroup->add(&enableGrpcServer);
grpcGroup->add(&defaultGrpcPortNumber);
#endif
caf::PdmUiGroup* octaveGroup = uiOrdering.addNewGroup("Octave");
octaveGroup->add(&octaveExecutable);
octaveGroup->add(&octaveShowHeaderInfoWhenExecutingScripts);

View File

@ -68,6 +68,9 @@ public:
public: // Pdm Fields
caf::PdmField<caf::AppEnum< RiaGuiApplication::RINavigationPolicy > > navigationPolicy;
caf::PdmField<bool> enableGrpcServer;
caf::PdmField<int> defaultGrpcPortNumber;
caf::PdmField<QString> scriptDirectories;
caf::PdmField<QString> scriptEditorExecutable;

View File

@ -56,6 +56,7 @@
bool RiaArgumentParser::parseArguments(cvf::ProgramOptions* progOpt)
{
CVF_ASSERT(progOpt);
progOpt->registerOption("grpcserver", "[<portnumber>]", "Run as a GRPC server. Default port is 50051", cvf::ProgramOptions::SINGLE_VALUE);
progOpt->registerOption("console", "", "Run as a console application without Graphics");
progOpt->registerOption("last", "", "Open last used project.");
progOpt->registerOption("project", "<filename>", "Open project file <filename>.", cvf::ProgramOptions::SINGLE_VALUE);

View File

@ -23,6 +23,9 @@ endif(Qt5Core_FOUND)
CONFIGURE_FILE( ${CMAKE_SOURCE_DIR}/ApplicationCode/Adm/RiaVersionInfo.h.cmake
${CMAKE_BINARY_DIR}/Generated/RiaVersionInfo.h
)
CONFIGURE_FILE( ${CMAKE_SOURCE_DIR}/ApplicationCode/Adm/RiaVersionInfo.py.cmake
${CMAKE_BINARY_DIR}/Python/generated/RiaVersionInfo.py
)
if (MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11))
# VS 2017 : Disable warnings from from gtest code, using deprecated code related to TR1
@ -44,6 +47,7 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/Commands
${CMAKE_CURRENT_SOURCE_DIR}/Commands/EclipseCommands
${CMAKE_CURRENT_SOURCE_DIR}/FileInterface
${CMAKE_CURRENT_SOURCE_DIR}/GrpcInterface
${CMAKE_CURRENT_SOURCE_DIR}/SocketInterface
${CMAKE_CURRENT_SOURCE_DIR}/Measurement
${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization
@ -97,6 +101,12 @@ list( APPEND CPP_SOURCES
${UNIT_TEST_FILES}
)
if (RESINSIGHT_ENABLE_GRPC)
list( APPEND REFERENCED_CMAKE_FILES
GrpcInterface/CMakeLists.cmake
)
endif(RESINSIGHT_ENABLE_GRPC)
list( APPEND REFERENCED_CMAKE_FILES
Application/CMakeLists_files.cmake
Application/Tools/CMakeLists_files.cmake
@ -152,7 +162,7 @@ list( APPEND REFERENCED_CMAKE_FILES
CommandFileInterface/Core/CMakeLists_files.cmake
Commands/FractureCommands/CMakeLists_files.cmake
)
option (RESINSIGHT_INCLUDE_APPLICATION_UNIT_TESTS "Include ApplicationCode Unit Tests" OFF)
if (RESINSIGHT_INCLUDE_APPLICATION_UNIT_TESTS)
add_definitions(-DUSE_UNIT_TESTS)
@ -230,7 +240,6 @@ if (RESINSIGHT_ENABLE_PROTOTYPE_FEATURE_SOURING)
add_definitions(-DENABLE_SOURING)
endif()
#############################################################################
# Qt specifics: Moc, ui, resources
#############################################################################
@ -306,11 +315,16 @@ source_group( "UnitTests" FILES ${UNIT_TEST_FILES} )
if (MSVC)
set( EXE_FILES WIN32)
if (RESINSIGHT_ENABLE_GRPC)
# GRPC generates a lot of harmless warnings on MSVC
set_source_files_properties(${GRPC_CPP_SOURCES} PROPERTIES COMPILE_FLAGS "/wd4251 /wd4702 /wd4005 /wd4244 /wd4125")
endif(RESINSIGHT_ENABLE_GRPC)
elseif (APPLE)
set( EXE_FILES MACOSX_BUNDLE)
endif()
set( EXE_FILES
${EXE_FILES}
${GRPC_HEADER_FILES}
${CPP_SOURCES}
${MOC_SOURCE_FILES}
${FORM_FILES_CPP}
@ -321,9 +335,23 @@ set( EXE_FILES
../ResInsightVersion.cmake
.clang-format
.clang-tidy
Adm/RiaVersionInfo.h.cmake
)
add_executable( ResInsight ${EXE_FILES} )
if (RESINSIGHT_ENABLE_GRPC)
list(APPEND EXE_FILES
${GRPC_CPP_SOURCES}
${GRPC_HEADER_FILES}
${GRPC_PYTHON_SOURCES_FULL_PATH}
Adm/RiaVersionInfo.py.cmake
)
if (DEFINED GRPC_LIBRARY_DIRS)
message(STATUS "Using GRPC Library Dir: ${GRPC_LIBRARY_DIRS}")
link_directories("${GRPC_LIBRARY_DIRS}")
endif(DEFINED GRPC_LIBRARY_DIRS)
endif(RESINSIGHT_ENABLE_GRPC)
add_executable( ResInsight ${EXE_FILES})
if (MSVC)
# The following warnings are supposed to be used in ResInsight, but temporarily disabled to avoid too much noise
@ -376,6 +404,10 @@ set( LINK_LIBRARIES
${QT_LIBRARIES}
)
if (RESINSIGHT_ENABLE_GRPC)
list(APPEND LINK_LIBRARIES ${GRPC_LIBRARIES})
endif()
# According to ivarun this is needed on OpenSuse, and Fedora. See: https://github.com/OPM/ResInsight/pull/7
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
list(APPEND EXTERNAL_LINK_LIBRARIES
@ -502,6 +534,31 @@ foreach (FILE_TO_COPY ${RI_DLL_FILENAMES})
endif()
endforeach()
# Copy all grpc libraries and python files
if (RESINSIGHT_ENABLE_GRPC)
if(UNIX)
foreach (GRPC_LIBRARY ${GRPC_LIBRARIES})
add_custom_command(TARGET ResInsight POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${GRPC_INSTALL_PREFIX}/lib/lib${GRPC_LIBRARY}.so"
"${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>"
)
endforeach(GRPC_LIBRARY ${GRPC_LIBRARIES})
endif(UNIX)
if (PYTHON_EXECUTABLE AND EXISTS ${PYTHON_EXECUTABLE})
add_custom_target(GeneratedPythonSources DEPENDS ${GRPC_GENERATED_PYTHON_SOURCES})
add_dependencies(ResInsight GeneratedPythonSources)
foreach (PYTHON_SCRIPT ${GRPC_PYTHON_SOURCES})
if (EXISTS "${GRPC_PYTHON_SOURCE_PATH}/${PYTHON_SCRIPT}")
configure_file("${GRPC_PYTHON_SOURCE_PATH}/${PYTHON_SCRIPT}"
"${GRPC_PYTHON_DEST_PATH}/${PYTHON_SCRIPT}"
COPYONLY)
endif(EXISTS "${GRPC_PYTHON_SOURCE_PATH}/${PYTHON_SCRIPT}")
endforeach(PYTHON_SCRIPT ${GRPC_PYTHON_SOURCES})
endif(PYTHON_EXECUTABLE AND EXISTS ${PYTHON_EXECUTABLE})
endif(RESINSIGHT_ENABLE_GRPC)
#############################################################################
# Install

View File

@ -38,6 +38,22 @@ RicfSetTimeStep::RicfSetTimeStep()
RICF_InitField(&m_timeStepIndex, "timeStep", -1, "Time Step Index", "", "", "");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicfSetTimeStep::setCaseId(int caseId)
{
m_caseId = caseId;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicfSetTimeStep::setTimeStepIndex(int timeStepIndex)
{
m_timeStepIndex = timeStepIndex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -66,5 +82,6 @@ void RicfSetTimeStep::execute()
for (Rim3dView* view : eclipseCase->views())
{
view->setCurrentTimeStepAndUpdate(m_timeStepIndex);
view->createDisplayModelAndRedraw();
}
}

View File

@ -34,9 +34,13 @@ class RicfSetTimeStep : public RicfCommandObject
public:
RicfSetTimeStep();
void setCaseId(int caseId);
void setTimeStepIndex(int timeStepIndex);
void execute() override;
private:
caf::PdmField<int> m_caseId;
caf::PdmField<int> m_timeStepIndex;
};

View File

@ -58,6 +58,7 @@ void RicEditPreferencesFeature::onActionTriggered(bool isChecked)
caf::PdmSettings::writeFieldsToApplicationStore(app->preferences());
app->applyPreferences(oldPreferences.get());
app->applyGuiPreferences(oldPreferences.get());
app->updateGrpcServer();
}
else
{

View File

@ -0,0 +1,158 @@
set ( SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcServer.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCallbacks.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCallbacks.inl
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcServiceInterface.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcGridInfoService.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcProjectInfoService.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCommandService.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcResInfoService.h
)
set ( SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcServer.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcServiceInterface.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcGridInfoService.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcProjectInfoService.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCommandService.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcResInfoService.cpp
)
add_definitions(-DENABLE_GRPC)
if (MSVC)
add_definitions(-D_WIN32_WINNT=0x600)
# Find Protobuf installation
# Looks for protobuf-config.cmake file installed by Protobuf's cmake installation.
set(protobuf_MODULE_COMPATIBLE ON CACHE BOOL "")
find_package(Protobuf CONFIG 3.0 REQUIRED)
message(STATUS "Using protobuf ${protobuf_VERSION}")
# Find gRPC installation
# Looks for gRPCConfig.cmake file installed by gRPC's cmake installation.
find_package(gRPC CONFIG REQUIRED NO_MODULE)
message(STATUS "Using gRPC ${gRPC_VERSION}")
set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf)
set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)
set(_GRPC_GRPCPP_UNSECURE gRPC::grpc++_unsecure gRPC::grpc_unsecure gRPC::gpr)
set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>)
set(GRPC_LIBRARIES ${_GRPC_GRPCPP_UNSECURE} ${_PROTOBUF_LIBPROTOBUF})
if (MSVC)
set_target_properties(${GRPC_LIBRARIES} PROPERTIES
MAP_IMPORTED_CONFIG_MINSIZEREL RELEASE
MAP_IMPORTED_CONFIG_RELWITHDEBINFO RELEASE
)
endif(MSVC)
else()
if (NOT DEFINED GRPC_INSTALL_PREFIX OR NOT EXISTS ${GRPC_INSTALL_PREFIX})
message(FATAL_ERROR "You need a valid GRPC_INSTALL_PREFIX set to build with GRPC")
endif()
set(ENV{PKG_CONFIG_PATH} "${GRPC_INSTALL_PREFIX}/lib/pkgconfig")
find_package(PkgConfig REQUIRED)
pkg_check_modules(GRPC REQUIRED grpc++_unsecure>=1.20 grpc_unsecure gpr protobuf)
set(_PROTOBUF_PROTOC "${GRPC_INSTALL_PREFIX}/bin/protoc")
set(_GRPC_CPP_PLUGIN_EXECUTABLE "${GRPC_INSTALL_PREFIX}/bin/grpc_cpp_plugin")
include_directories(AFTER ${GRPC_INCLUDE_DIRS})
endif()
# Cannot use the nice new FindPackage modules for python since that is CMake 3.12+
if(PYTHON_EXECUTABLE AND EXISTS ${PYTHON_EXECUTABLE})
message(STATUS "Using Python ${PYTHON_EXECUTABLE}")
endif(PYTHON_EXECUTABLE AND EXISTS ${PYTHON_EXECUTABLE})
# Proto files
set(PROTO_FILES
"Empty"
"CaseInfo"
"GridInfo"
"ProjectInfo"
"Commands"
"ResInfo"
)
set(GRPC_PYTHON_SOURCE_PATH "${CMAKE_SOURCE_DIR}/Python")
set(GRPC_PYTHON_DEST_PATH "${CMAKE_BINARY_DIR}/Python")
foreach(proto_file ${PROTO_FILES})
get_filename_component(rips_proto "${CMAKE_CURRENT_LIST_DIR}/GrpcProtos/${proto_file}.proto" ABSOLUTE)
get_filename_component(rips_proto_path "${rips_proto}" PATH)
set(rips_proto_srcs "${CMAKE_BINARY_DIR}/Generated/${proto_file}.pb.cc")
set(rips_proto_hdrs "${CMAKE_BINARY_DIR}/Generated/${proto_file}.pb.h")
set(rips_grpc_srcs "${CMAKE_BINARY_DIR}/Generated/${proto_file}.grpc.pb.cc")
set(rips_grpc_hdrs "${CMAKE_BINARY_DIR}/Generated/${proto_file}.grpc.pb.h")
add_custom_command(
OUTPUT "${rips_proto_srcs}" "${rips_proto_hdrs}" "${rips_grpc_srcs}" "${rips_grpc_hdrs}"
COMMAND ${_PROTOBUF_PROTOC}
ARGS --grpc_out "${CMAKE_BINARY_DIR}/Generated"
--cpp_out "${CMAKE_BINARY_DIR}/Generated"
-I "${rips_proto_path}"
--plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}"
"${rips_proto}"
DEPENDS "${rips_proto}"
)
if (PYTHON_EXECUTABLE AND EXISTS ${PYTHON_EXECUTABLE})
set(rips_proto_python "generated/${proto_file}_pb2.py")
set(rips_grpc_python "generated/${proto_file}_pb2_grpc.py")
add_custom_command(
OUTPUT "${GRPC_PYTHON_SOURCE_PATH}/${rips_proto_python}" "${GRPC_PYTHON_SOURCE_PATH}/${rips_grpc_python}"
COMMAND ${PYTHON_EXECUTABLE}
ARGS -m grpc_tools.protoc
-I "${rips_proto_path}"
--python_out "${GRPC_PYTHON_SOURCE_PATH}/generated"
--grpc_python_out "${GRPC_PYTHON_SOURCE_PATH}/generated"
"${rips_proto}"
DEPENDS "${rips_proto}"
COMMENT "Generating ${rips_proto_python} and ${rips_grpc_python}"
VERBATIM
)
list (APPEND GRPC_PYTHON_GENERATED_SOURCES
${rips_proto_python}
${rips_grpc_python}
)
endif(PYTHON_EXECUTABLE AND EXISTS ${PYTHON_EXECUTABLE})
list( APPEND GRPC_HEADER_FILES
${rips_proto_hdrs}
${rips_grpc_hdrs}
)
list( APPEND GRPC_CPP_SOURCES
${rips_proto_srcs}
${rips_grpc_srcs}
)
endforeach(proto_file)
if (PYTHON_EXECUTABLE AND EXISTS ${PYTHON_EXECUTABLE})
list(APPEND GRPC_PYTHON_SOURCES
${GRPC_PYTHON_GENERATED_SOURCES}
"api/__init__.py"
"api/ResInsight.py"
"examples/CommandExample.py"
"examples/GridInfoStreamingExample.py"
"examples/ResultValues.py"
"examples/SelectedCases.py"
"examples/AllCases.py"
"tests/test_sample.py"
)
foreach(PYTHON_SCRIPT ${GRPC_PYTHON_SOURCES})
list(APPEND GRPC_PYTHON_SOURCES_FULL_PATH "${GRPC_PYTHON_SOURCE_PATH}/${PYTHON_SCRIPT}")
endforeach()
source_group(TREE ${GRPC_PYTHON_SOURCE_PATH} FILES ${GRPC_PYTHON_SOURCES_FULL_PATH} PREFIX "Python")
endif(PYTHON_EXECUTABLE AND EXISTS ${PYTHON_EXECUTABLE})
list ( APPEND GRPC_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
list ( APPEND GRPC_CPP_SOURCES ${SOURCE_GROUP_SOURCE_FILES})
source_group( "GrpcInterface" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.cmake )

View File

@ -0,0 +1,31 @@
syntax = "proto3";
package rips;
message Case {
int32 id = 1;
}
message CaseInfo
{
int32 id = 1;
int32 group_id = 2;
string name = 3;
string type = 4;
}
message CaseInfos
{
repeated CaseInfo case_info = 1;
}
message CaseGroup
{
int32 id = 1;
string name = 2;
}
message CaseGroups
{
repeated CaseGroup case_group = 1;
}

View File

@ -0,0 +1,60 @@
syntax = "proto3";
import "Empty.proto";
package rips;
service Commands
{
rpc Execute(CommandParams) returns(Empty) {}
}
message SetTimeStepParams
{
int32 caseId = 1;
int32 timeStep = 2;
}
message SetMainWindowSizeParams
{
int32 height = 1;
int32 width = 2;
}
message FilePathRequest
{
string path = 1;
}
message ReplaceCaseRequest
{
string newGridFile = 1;
int32 caseId = 2;
}
message ReplaceSourceCasesRequest
{
string gridListFile = 1;
}
message ExportMultiCaseRequest
{
string gridListFile = 1;
}
message CommandParams
{
oneof params
{
SetTimeStepParams setTimeStep = 1;
SetMainWindowSizeParams setMainWindowSize = 2;
FilePathRequest openProject = 3;
Empty closeProject = 4;
FilePathRequest setStartDir = 5;
FilePathRequest loadCase = 6;
ReplaceCaseRequest replaceCase = 7;
ReplaceSourceCasesRequest replaceSourceCases = 8;
ExportMultiCaseRequest exportMultiCaseSnapshots = 9;
}
}

View File

@ -0,0 +1,7 @@
syntax = "proto3";
package rips;
message Empty
{
}

View File

@ -0,0 +1,89 @@
syntax = "proto3";
import "CaseInfo.proto";
package rips;
service GridInfo
{
// This function returns a two dimensional matrix: One row for each grid, starting with the main grid.
rpc GetGridCount(Case) returns(GridCount) {}
rpc GetGridDimensions(Case) returns (GridDimensions) {}
rpc StreamActiveCellInfo(ActiveCellInfoRequest) returns (stream ActiveCellInfoArray) {}
rpc GetAllCoarseningInfoArray(Case) returns (CoarseningInfoArray) {}
rpc GetTimeSteps(Case) returns (TimeStepDates) {}
rpc GetTimeStepDaysSinceStart(Case) returns (DoubleDates) {}
}
message GridCount
{
int32 count = 1;
}
message GridDimensions
{
repeated Vec3i dimensions = 1;
}
message Vec3i {
int32 i = 1;
int32 j = 2;
int32 k = 3;
}
enum PorosityModelType
{
MATRIX_MODEL = 0;
FRACTURE_MODEL = 1;
}
message ActiveCellInfoRequest
{
int32 case_id = 1;
PorosityModelType porosity_model = 2;
}
message ActiveCellInfoArray
{
repeated ActiveCellInfo data = 1;
}
message ActiveCellInfo
{
int32 grid_index = 1;
int32 parent_grid_index = 2;
int32 coarsening_box_index = 3;
Vec3i local_ijk = 4;
Vec3i parent_ijk = 5;
}
message CoarseningInfoArray
{
repeated CoarseningInfo data = 1;
}
message CoarseningInfo
{
Vec3i min = 1;
Vec3i max = 2;
}
message TimeStepDates
{
repeated TimeStepDate date = 1;
}
message TimeStepDate
{
int32 year = 1;
int32 month = 2;
int32 day = 3;
int32 hour = 4;
int32 minute = 5;
int32 second = 6;
}
message DoubleDates
{
repeated double date_decimal = 1;
}

View File

@ -0,0 +1,16 @@
syntax = "proto3";
import "CaseInfo.proto";
import "Empty.proto";
package rips;
service ProjectInfo {
rpc CurrentCase(Empty) returns (Case) {}
rpc CurrentCaseInfo(Empty) returns (CaseInfo) {}
rpc CaseInfoFromCase(Case) returns (CaseInfo) {}
rpc SelectedCases(Empty) returns (CaseInfos) {}
rpc AllCaseGroups(Empty) returns (CaseGroups) {}
rpc AllCases(Empty) returns (CaseInfos) {}
rpc CasesInGroup(CaseGroup) returns (CaseInfos) {}
}

View File

@ -0,0 +1,15 @@
syntax = "proto3";
package rips;
import "Empty.proto";
service ResInfo {
rpc GetVersion(Empty) returns (Version) {}
}
message Version {
int32 major_version = 1;
int32 minor_version = 2;
int32 patch_version = 3;
}

View File

@ -0,0 +1,173 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RiaLogging.h"
#include <QString>
#include <grpc/support/log.h>
#include <grpcpp/grpcpp.h>
using grpc::CompletionQueue;
using grpc::ServerAsyncResponseWriter;
using grpc::ServerAsyncWriter;
using grpc::ServerCompletionQueue;
using grpc::ServerContext;
using grpc::ServerWriter;
using grpc::Status;
class RiaGrpcServiceInterface;
//==================================================================================================
//
// Base class for all gRPC-callbacks
//
//==================================================================================================
class RiaAbstractGrpcCallback
{
public:
enum CallState
{
CREATE_HANDLER,
INIT_REQUEST,
PROCESS_REQUEST,
FINISH_REQUEST
};
public:
inline RiaAbstractGrpcCallback();
virtual ~RiaAbstractGrpcCallback() {}
virtual QString name() const = 0;
virtual RiaAbstractGrpcCallback* createNewFromThis() const = 0;
virtual void createRequestHandler(ServerCompletionQueue* completionQueue) = 0;
virtual void initRequest() = 0;
virtual void processRequest() = 0;
virtual void finishRequest() {}
inline CallState callState() const;
inline const Status& status() const;
protected:
inline void setCallState(CallState state);
protected:
CallState m_state;
Status m_status;
};
//==================================================================================================
//
// Templated gRPC-callback base class
//
//==================================================================================================
template<typename ServiceT, typename RequestT, typename ReplyT>
class RiaGrpcRequestCallback : public RiaAbstractGrpcCallback
{
public:
RiaGrpcRequestCallback(ServiceT* service);
QString name() const override;
const RequestT& request() const;
ReplyT& reply();
protected:
virtual QString methodType() const = 0;
protected:
ServiceT* m_service;
RequestT m_request;
ReplyT m_reply;
};
//==================================================================================================
//
// Templated gRPC-callback for non-streaming services
//
//==================================================================================================
template<typename ServiceT, typename RequestT, typename ReplyT>
class RiaGrpcCallback : public RiaGrpcRequestCallback<ServiceT, RequestT, ReplyT>
{
public:
typedef ServerAsyncResponseWriter<ReplyT> ResponseWriterT;
typedef std::function<Status(ServiceT&, ServerContext*, const RequestT*, ReplyT*)> MethodImplT;
typedef std::function<
void(ServiceT&, ServerContext*, RequestT*, ResponseWriterT*, CompletionQueue*, ServerCompletionQueue*, void*)>
MethodRequestT;
RiaGrpcCallback(ServiceT* service, MethodImplT methodImpl, MethodRequestT methodRequest);
RiaAbstractGrpcCallback* createNewFromThis() const override;
void createRequestHandler(ServerCompletionQueue* completionQueue) override;
void initRequest() override;
void processRequest() override;
protected:
virtual QString methodType() const;
private:
ServerContext m_context;
ResponseWriterT m_responder;
MethodImplT m_methodImpl;
MethodRequestT m_methodRequest;
};
//==================================================================================================
//
// Templated *streaming* gRPC-callback calling service implementation callbacks
//
// The streaming callback needs a state handler for setting up and maintaining order.
//
// A fully functional stream handler needs to implement the following methods:
// 1. Default Constructor
// 2. grpc::Status init(const grpc::Message* request)
// 3. grpc::status assignReply(grpc::Message* reply)
//
//==================================================================================================
//==================================================================================================
template<typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
class RiaGrpcStreamCallback : public RiaGrpcRequestCallback<ServiceT, RequestT, ReplyT>
{
public:
typedef ServerAsyncWriter<ReplyT> ResponseWriterT;
typedef std::function<Status(ServiceT&, ServerContext*, const RequestT*, ReplyT*, StateHandlerT*)> MethodImplT;
typedef std::function<
void(ServiceT&, ServerContext*, RequestT*, ResponseWriterT*, CompletionQueue*, ServerCompletionQueue*, void*)>
MethodRequestT;
RiaGrpcStreamCallback(ServiceT* service, MethodImplT methodImpl, MethodRequestT methodRequest, StateHandlerT* stateHandler);
RiaAbstractGrpcCallback* createNewFromThis() const override;
void createRequestHandler(ServerCompletionQueue* completionQueue) override;
void initRequest() override;
void processRequest() override;
protected:
virtual QString methodType() const;
private:
ServerContext m_context;
ResponseWriterT m_responder;
MethodImplT m_methodImpl;
MethodRequestT m_methodRequest;
size_t m_dataCount; // This is used to keep track of progress. Only one item is sent for each invocation.
std::unique_ptr<StateHandlerT> m_stateHandler;
};
#include "RiaGrpcCallbacks.inl"

View File

@ -0,0 +1,239 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
inline RiaAbstractGrpcCallback::RiaAbstractGrpcCallback()
: m_state(CREATE_HANDLER)
, m_status(Status::OK)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaAbstractGrpcCallback::CallState RiaAbstractGrpcCallback::callState() const
{
return m_state;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const Status& RiaAbstractGrpcCallback::status() const
{
return m_status;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
inline void RiaAbstractGrpcCallback::setCallState(CallState state)
{
m_state = state;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT>
RiaGrpcRequestCallback<ServiceT, RequestT, ReplyT>::RiaGrpcRequestCallback(ServiceT* service)
: m_service(service)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT>
QString RiaGrpcRequestCallback<ServiceT, RequestT, ReplyT>::name() const
{
QString fullName = QString("%1:%2(%3, %4)")
.arg(typeid(ServiceT).name())
.arg(methodType())
.arg(typeid(RequestT).name())
.arg(typeid(ReplyT).name());
return fullName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT>
const RequestT& RiaGrpcRequestCallback<ServiceT, RequestT, ReplyT>::request() const
{
return m_request;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT>
ReplyT& RiaGrpcRequestCallback<ServiceT, RequestT, ReplyT>::reply()
{
return m_reply;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT>
RiaGrpcCallback<ServiceT, RequestT, ReplyT>::RiaGrpcCallback(ServiceT* service,
MethodImplT methodImpl,
MethodRequestT methodRequest)
: RiaGrpcRequestCallback<ServiceT, RequestT, ReplyT>(service)
, m_responder(&m_context)
, m_methodImpl(methodImpl)
, m_methodRequest(methodRequest)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT>
RiaAbstractGrpcCallback* RiaGrpcCallback<ServiceT, RequestT, ReplyT>::createNewFromThis() const
{
return new RiaGrpcCallback<ServiceT, RequestT, ReplyT>(this->m_service, this->m_methodImpl, this->m_methodRequest);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT>
void RiaGrpcCallback<ServiceT, RequestT, ReplyT>::createRequestHandler(ServerCompletionQueue* completionQueue)
{
m_methodRequest(*this->m_service, &m_context, &this->m_request, &m_responder, completionQueue, completionQueue, this);
this->setCallState(RiaAbstractGrpcCallback::INIT_REQUEST);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT>
void RiaGrpcCallback<ServiceT, RequestT, ReplyT>::initRequest()
{
this->setCallState(RiaAbstractGrpcCallback::PROCESS_REQUEST);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT>
void RiaGrpcCallback<ServiceT, RequestT, ReplyT>::processRequest()
{
this->m_status = m_methodImpl(*this->m_service, &m_context, &this->m_request, &this->m_reply);
m_responder.Finish(this->m_reply, this->m_status, this);
this->setCallState(RiaAbstractGrpcCallback::FINISH_REQUEST);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT>
QString RiaGrpcCallback<ServiceT, RequestT, ReplyT>::methodType() const
{
return "RegularMethod";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
RiaGrpcStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::RiaGrpcStreamCallback(ServiceT* service,
MethodImplT methodImpl,
MethodRequestT methodRequest,
StateHandlerT* stateHandler)
: RiaGrpcRequestCallback<ServiceT, RequestT, ReplyT>(service)
, m_responder(&m_context)
, m_methodImpl(methodImpl)
, m_methodRequest(methodRequest)
, m_dataCount(0u)
, m_stateHandler(stateHandler)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
RiaAbstractGrpcCallback* RiaGrpcStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::createNewFromThis() const
{
return new RiaGrpcStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>(
this->m_service, m_methodImpl, m_methodRequest, new StateHandlerT);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
void RiaGrpcStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::createRequestHandler(
ServerCompletionQueue* completionQueue)
{
m_methodRequest(*this->m_service, &m_context, &this->m_request, &m_responder, completionQueue, completionQueue, this);
this->setCallState(RiaAbstractGrpcCallback::INIT_REQUEST);
}
//--------------------------------------------------------------------------------------------------
/// Perform initialisation tasks at the time of receiving a request
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
void RiaGrpcStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::initRequest()
{
this->m_status = m_stateHandler->init(&this->m_request);
this->setCallState(RiaAbstractGrpcCallback::PROCESS_REQUEST);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
void RiaGrpcStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::processRequest()
{
this->m_reply = ReplyT(); // Make sure it is reset
if (!this->m_status.ok())
{
m_responder.Finish(this->m_status, this);
this->setCallState(RiaAbstractGrpcCallback::FINISH_REQUEST);
return;
}
this->m_status = m_methodImpl(*this->m_service, &m_context, &this->m_request, &this->m_reply, m_stateHandler.get());
if (this->m_status.ok())
{
m_responder.Write(this->m_reply, this);
}
else
{
this->setCallState(RiaAbstractGrpcCallback::FINISH_REQUEST);
// Out of range means we're finished but it isn't an error
if (this->m_status.error_code() == grpc::OUT_OF_RANGE)
{
this->m_status = Status::OK;
}
m_responder.Finish(this->m_status, this);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template<typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
QString RiaGrpcStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::methodType() const
{
return "StreamingMethod";
}

View File

@ -0,0 +1,155 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#include "RiaGrpcCommandService.h"
#include "RiaLogging.h"
#include "RiaGrpcCallbacks.h"
#include "RicfSetTimeStep.h"
#include "cafAssert.h"
#include "cafPdmDefaultObjectFactory.h"
#include "cafPdmValueField.h"
using namespace rips;
using namespace google::protobuf;
#ifdef WIN32
#ifdef GetMessage
#undef GetMessage
#endif
#endif
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcCommandService::Execute(grpc::ServerContext* context, const CommandParams* request, Empty* reply)
{
auto requestDescriptor = request->GetDescriptor();
RiaLogging::info(QString::fromStdString(requestDescriptor->name()));
CommandParams::ParamsCase paramsCase = request->params_case();
if (paramsCase != CommandParams::PARAMS_NOT_SET)
{
auto grpcOneOfMessage = requestDescriptor->FindFieldByNumber((int)paramsCase);
CAF_ASSERT(grpcOneOfMessage->type() == FieldDescriptor::TYPE_MESSAGE);
const Message& params = request->GetReflection()->GetMessage(*request, grpcOneOfMessage);
QString grpcOneOfMessageName = QString::fromStdString(grpcOneOfMessage->name());
RiaLogging::info(QString("Found Command: %1").arg(grpcOneOfMessageName));
auto pdmObjectHandle = caf::PdmDefaultObjectFactory::instance()->create(grpcOneOfMessageName);
auto commandHandle = dynamic_cast<RicfCommandObject*>(pdmObjectHandle);
if (commandHandle)
{
auto subMessageDescriptor = grpcOneOfMessage->message_type();
int numParameters = subMessageDescriptor->field_count();
for (int i = 0; i < numParameters; ++i)
{
auto parameter = subMessageDescriptor->field(i);
if (parameter)
{
QString parameterName = QString::fromStdString(parameter->name());
auto pdmValueFieldHandle = dynamic_cast<caf::PdmValueField*>(pdmObjectHandle->findField(parameterName));
if (pdmValueFieldHandle)
{
RiaLogging::info(QString("Found Matching Parameter: %1").arg(parameterName));
assignFieldValue(pdmValueFieldHandle, params, parameter);
}
}
}
commandHandle->execute();
return Status::OK;
}
}
return grpc::Status(grpc::NOT_FOUND, "Command not found");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RiaAbstractGrpcCallback*> RiaGrpcCommandService::createCallbacks()
{
typedef RiaGrpcCommandService Self;
return {new RiaGrpcCallback<Self, CommandParams, Empty>(this, &Self::Execute, &Self::RequestExecute)};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcCommandService::assignFieldValue(caf::PdmValueField* pdmValueField,
const Message& params,
const FieldDescriptor* paramDescriptor)
{
FieldDescriptor::Type fieldDataType = paramDescriptor->type();
QVariant qValue;
switch (fieldDataType)
{
case FieldDescriptor::TYPE_BOOL: {
auto value = params.GetReflection()->GetBool(params, paramDescriptor);
qValue = QVariant(value);
break;
}
case FieldDescriptor::TYPE_INT32: {
int value = params.GetReflection()->GetInt32(params, paramDescriptor);
qValue = QVariant(value);
break;
}
case FieldDescriptor::TYPE_UINT32: {
uint value = params.GetReflection()->GetUInt32(params, paramDescriptor);
qValue = QVariant(value);
break;
}
case FieldDescriptor::TYPE_INT64: {
int64_t value = params.GetReflection()->GetInt64(params, paramDescriptor);
qValue = QVariant((qlonglong) value);
break;
}
case FieldDescriptor::TYPE_UINT64: {
uint64_t value = params.GetReflection()->GetUInt64(params, paramDescriptor);
qValue = QVariant((qulonglong) value);
break;
}
case FieldDescriptor::TYPE_STRING: {
auto value = params.GetReflection()->GetString(params, paramDescriptor);
qValue = QVariant(QString::fromStdString(value));
break;
}
case FieldDescriptor::TYPE_FLOAT: {
auto value = params.GetReflection()->GetFloat(params, paramDescriptor);
qValue = QVariant(value);
break;
}
case FieldDescriptor::TYPE_DOUBLE: {
auto value = params.GetReflection()->GetDouble(params, paramDescriptor);
qValue = QVariant(value);
break;
}
case FieldDescriptor::TYPE_ENUM: {
auto value = params.GetReflection()->GetEnumValue(params, paramDescriptor);
qValue = QVariant(value);
break;
}
}
pdmValueField->setFromQVariant(qValue);
}
static bool RiaGrpcCommandService_init =
RiaGrpcServiceFactory::instance()->registerCreator<RiaGrpcCommandService>(typeid(RiaGrpcCommandService).hash_code());

View File

@ -0,0 +1,58 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RiaGrpcServiceInterface.h"
#include "Commands.grpc.pb.h"
#include <grpcpp/grpcpp.h>
#include <vector>
namespace rips
{
class Empty;
}
namespace caf
{
class PdmValueField;
}
namespace google
{
namespace protobuf
{
class FieldDescriptor;
class Message;
} // namespace protobuf
} // namespace google
class RiaAbstractGrpcCallback;
class RiaGrpcCommandService : public rips::Commands::AsyncService, public RiaGrpcServiceInterface
{
public:
grpc::Status Execute(grpc::ServerContext* context, const rips::CommandParams* request, rips::Empty* reply) override;
std::vector<RiaAbstractGrpcCallback*> createCallbacks() override;
private:
void assignFieldValue(caf::PdmValueField* pdmValueField,
const google::protobuf::Message& params,
const google::protobuf::FieldDescriptor* paramDescriptor);
};

View File

@ -0,0 +1,283 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#include "RiaGrpcGridInfoService.h"
#include "RiaGrpcCallbacks.h"
#include "RigActiveCellInfo.h"
#include "RigEclipseCaseData.h"
#include "RigMainGrid.h"
#include "RimEclipseCase.h"
#include "RimGeoMechCase.h"
#include <string.h> // memcpy
using namespace rips;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaActiveCellInfoStateHandler::RiaActiveCellInfoStateHandler()
: m_request(nullptr)
, m_eclipseCase(nullptr)
, m_activeCellInfo(nullptr)
, m_currentCellIdx(0u)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaActiveCellInfoStateHandler::init(const rips::ActiveCellInfoRequest* request)
{
CAF_ASSERT(request);
m_request = request;
m_porosityModel = RiaDefines::PorosityModelType(m_request->porosity_model());
RimCase* rimCase = RiaGrpcServiceInterface::findCase(m_request->case_id());
m_eclipseCase = dynamic_cast<RimEclipseCase*>(rimCase);
if (!m_eclipseCase)
{
return grpc::Status(grpc::NOT_FOUND, "Eclipse Case not found");
}
if (!m_eclipseCase->eclipseCaseData() || !m_eclipseCase->eclipseCaseData()->mainGrid())
{
return grpc::Status(grpc::NOT_FOUND, "Eclipse Case Data not found");
}
m_activeCellInfo = m_eclipseCase->eclipseCaseData()->activeCellInfo(m_porosityModel);
if (!m_activeCellInfo)
{
return grpc::Status(grpc::NOT_FOUND, "Active Cell Info not found");
}
size_t globalCoarseningBoxCount = 0;
for (size_t gridIdx = 0; gridIdx < m_eclipseCase->eclipseCaseData()->gridCount(); gridIdx++)
{
m_globalCoarseningBoxIndexStart.push_back(globalCoarseningBoxCount);
RigGridBase* grid = m_eclipseCase->eclipseCaseData()->grid(gridIdx);
size_t localCoarseningBoxCount = grid->coarseningBoxCount();
globalCoarseningBoxCount += localCoarseningBoxCount;
}
return grpc::Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaActiveCellInfoStateHandler::assignNextActiveCellInfoData(rips::ActiveCellInfo* cellInfo)
{
const std::vector<RigCell>& reservoirCells = m_eclipseCase->eclipseCaseData()->mainGrid()->globalCellArray();
while (m_currentCellIdx < reservoirCells.size())
{
size_t cellIdxToTry = m_currentCellIdx++;
if (m_activeCellInfo->isActive(cellIdxToTry))
{
assignActiveCellInfoData(cellInfo, reservoirCells, cellIdxToTry);
return grpc::Status::OK;
}
}
return Status(grpc::OUT_OF_RANGE, "We've reached the end. This is not an error but means transmission is finished");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaActiveCellInfoStateHandler::assignActiveCellInfoData(rips::ActiveCellInfo* cellInfo,
const std::vector<RigCell>& reservoirCells,
size_t cellIdx)
{
RigGridBase* grid = reservoirCells[cellIdx].hostGrid();
CVF_ASSERT(grid != nullptr);
size_t cellIndex = reservoirCells[cellIdx].gridLocalCellIndex();
size_t i, j, k;
grid->ijkFromCellIndex(cellIndex, &i, &j, &k);
size_t pi, pj, pk;
RigGridBase* parentGrid = nullptr;
if (grid->isMainGrid())
{
pi = i;
pj = j;
pk = k;
parentGrid = grid;
}
else
{
size_t parentCellIdx = reservoirCells[cellIdx].parentCellIndex();
parentGrid = (static_cast<RigLocalGrid*>(grid))->parentGrid();
CVF_ASSERT(parentGrid != nullptr);
parentGrid->ijkFromCellIndex(parentCellIdx, &pi, &pj, &pk);
}
cellInfo->set_grid_index((int)grid->gridIndex());
cellInfo->set_parent_grid_index((int)parentGrid->gridIndex());
size_t coarseningIdx = reservoirCells[cellIdx].coarseningBoxIndex();
if (coarseningIdx != cvf::UNDEFINED_SIZE_T)
{
size_t globalCoarseningIdx = m_globalCoarseningBoxIndexStart[grid->gridIndex()] + coarseningIdx;
cellInfo->set_coarsening_box_index((int)globalCoarseningIdx);
}
else
{
cellInfo->set_coarsening_box_index(-1);
}
{
rips::Vec3i* local_ijk = new rips::Vec3i;
local_ijk->set_i((int)i);
local_ijk->set_j((int)j);
local_ijk->set_k((int)k);
cellInfo->set_allocated_local_ijk(local_ijk);
}
{
rips::Vec3i* parent_ijk = new rips::Vec3i;
parent_ijk->set_i((int)pi);
parent_ijk->set_j((int)pj);
parent_ijk->set_k((int)pk);
cellInfo->set_allocated_parent_ijk(parent_ijk);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigActiveCellInfo* RiaActiveCellInfoStateHandler::activeCellInfo() const
{
return m_activeCellInfo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<RigCell>& RiaActiveCellInfoStateHandler::reservoirCells() const
{
const std::vector<RigCell>& reservoirCells = m_eclipseCase->eclipseCaseData()->mainGrid()->globalCellArray();
return reservoirCells;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaActiveCellInfoStateHandler::assignReply(rips::ActiveCellInfoArray* reply)
{
const size_t packageSize = RiaGrpcServiceInterface::numberOfMessagesForByteCount(sizeof(rips::ActiveCellInfoArray));
size_t packageIndex = 0u;
reply->mutable_data()->Reserve((int)packageSize);
for (; packageIndex < packageSize && m_currentCellIdx < m_activeCellInfo->reservoirCellCount(); ++packageIndex)
{
rips::ActiveCellInfo singleCellInfo;
grpc::Status singleCellInfoStatus = assignNextActiveCellInfoData(&singleCellInfo);
if (singleCellInfoStatus.ok())
{
rips::ActiveCellInfo* allocCellInfo = reply->add_data();
*allocCellInfo = singleCellInfo;
}
else
{
break;
}
}
if (packageIndex > 0u)
{
return Status::OK;
}
return Status(grpc::OUT_OF_RANGE, "We've reached the end. This is not an error but means transmission is finished");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcGridInfoService::GetGridCount(grpc::ServerContext* context, const rips::Case* request, rips::GridCount* reply)
{
RimCase* rimCase = findCase(request->id());
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>(rimCase);
size_t gridCount = 0u;
if (eclipseCase)
{
gridCount = eclipseCase->mainGrid()->gridCount();
reply->set_count((int)gridCount);
return Status::OK;
}
return grpc::Status(grpc::NOT_FOUND, "Eclipse Case not found");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcGridInfoService::GetGridDimensions(grpc::ServerContext* context,
const rips::Case* request,
rips::GridDimensions* reply)
{
RimCase* rimCase = findCase(request->id());
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>(rimCase);
if (eclipseCase)
{
size_t gridCount = eclipseCase->mainGrid()->gridCount();
for (size_t i = 0; i < gridCount; ++i)
{
const RigGridBase* grid = eclipseCase->mainGrid()->gridByIndex(i);
rips::Vec3i* dimensions = reply->add_dimensions();
dimensions->set_i((int)grid->cellCountI());
dimensions->set_j((int)grid->cellCountJ());
dimensions->set_k((int)grid->cellCountK());
}
return grpc::Status::OK;
}
return grpc::Status(grpc::NOT_FOUND, "Eclipse Case not found");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcGridInfoService::StreamActiveCellInfo(grpc::ServerContext* context,
const rips::ActiveCellInfoRequest* request,
rips::ActiveCellInfoArray* reply,
RiaActiveCellInfoStateHandler* stateHandler)
{
return stateHandler->assignReply(reply);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RiaAbstractGrpcCallback*> RiaGrpcGridInfoService::createCallbacks()
{
typedef RiaGrpcGridInfoService Self;
return {new RiaGrpcCallback<Self, Case, GridCount>(this, &Self::GetGridCount, &Self::RequestGetGridCount),
new RiaGrpcCallback<Self, Case, GridDimensions>(this, &Self::GetGridDimensions, &Self::RequestGetGridDimensions),
new RiaGrpcStreamCallback<Self, ActiveCellInfoRequest, ActiveCellInfoArray, RiaActiveCellInfoStateHandler>(
this, &Self::StreamActiveCellInfo, &Self::RequestStreamActiveCellInfo, new RiaActiveCellInfoStateHandler)};
}
static bool RiaGrpcGridInfoService_init =
RiaGrpcServiceFactory::instance()->registerCreator<RiaGrpcGridInfoService>(typeid(RiaGrpcGridInfoService).hash_code());

View File

@ -0,0 +1,80 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "GridInfo.grpc.pb.h"
#include "RiaGrpcServiceInterface.h"
#include "RiaPorosityModel.h"
#include <vector>
namespace rips
{
class Case;
}
class RiaAbstractGrpcCallback;
class RigCell;
class RigActiveCellInfo;
class RimEclipseCase;
//==================================================================================================
//
// State handler for streaming of active cell info
//
//==================================================================================================
class RiaActiveCellInfoStateHandler
{
public:
typedef grpc::Status Status;
RiaActiveCellInfoStateHandler();
Status init(const rips::ActiveCellInfoRequest* request);
Status assignNextActiveCellInfoData(rips::ActiveCellInfo* cellInfo);
void assignActiveCellInfoData(rips::ActiveCellInfo* cellInfo, const std::vector<RigCell>& reservoirCells, size_t cellIdx);
Status assignReply(rips::ActiveCellInfoArray* reply);
RigActiveCellInfo* activeCellInfo() const;
const std::vector<RigCell>& reservoirCells() const;
protected:
const rips::ActiveCellInfoRequest* m_request;
RimEclipseCase* m_eclipseCase;
RiaDefines::PorosityModelType m_porosityModel;
RigActiveCellInfo* m_activeCellInfo;
std::vector<size_t> m_globalCoarseningBoxIndexStart;
size_t m_currentCellIdx;
};
//==================================================================================================
//
// gRPC-service answering requests about grid information for a given case
//
//==================================================================================================
class RiaGrpcGridInfoService final : public rips::GridInfo::AsyncService, public RiaGrpcServiceInterface
{
public:
grpc::Status GetGridCount(grpc::ServerContext* context, const rips::Case* request, rips::GridCount* reply) override;
grpc::Status GetGridDimensions(grpc::ServerContext* context, const rips::Case* request, rips::GridDimensions* reply) override;
grpc::Status StreamActiveCellInfo(grpc::ServerContext* context,
const rips::ActiveCellInfoRequest* request,
rips::ActiveCellInfoArray* reply,
RiaActiveCellInfoStateHandler* stateHandler);
std::vector<RiaAbstractGrpcCallback*> createCallbacks() override;
};

View File

@ -0,0 +1,249 @@
#include "RiaGrpcProjectInfoService.h"
#include "RiaApplication.h"
#include "RiaGrpcCallbacks.h"
#include "RiaSocketTools.h"
#include "RimCase.h"
#include "RimCaseCollection.h"
#include "RimEclipseCase.h"
#include "RimEclipseCaseCollection.h"
#include "RimGeoMechCase.h"
#include "RimGridView.h"
#include "RimIdenticalGridCaseGroup.h"
#include "RimOilField.h"
#include "RimProject.h"
#include "cafSelectionManager.h"
#include "CaseInfo.grpc.pb.h"
using grpc::ServerCompletionQueue;
using grpc::ServerContext;
using grpc::Status;
using namespace rips;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Status RiaGrpcProjectInfoService::CurrentCase(ServerContext* context, const rips::Empty* request, rips::Case* reply)
{
RimGridView* view = RiaApplication::instance()->activeGridView();
if (view)
{
RimCase* currentCase = view->ownerCase();
if (currentCase)
{
reply->set_id(currentCase->caseId());
return Status::OK;
}
}
return Status(grpc::NOT_FOUND, "No current case found");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Status RiaGrpcProjectInfoService::CurrentCaseInfo(ServerContext* context, const rips::Empty* request, rips::CaseInfo* reply)
{
RimGridView* view = RiaApplication::instance()->activeGridView();
if (view)
{
RimCase* currentCase = view->ownerCase();
if (currentCase)
{
qint64 caseId = currentCase->caseId();
qint64 caseGroupId = -1;
QString caseName, caseType;
RiaSocketTools::getCaseInfoFromCase(currentCase, caseId, caseName, caseType, caseGroupId);
reply->set_id(caseId);
reply->set_group_id(caseGroupId);
reply->set_name(caseName.toStdString());
reply->set_type(caseType.toStdString());
return Status::OK;
}
}
return Status(grpc::NOT_FOUND, "No current case found");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status
RiaGrpcProjectInfoService::CaseInfoFromCase(grpc::ServerContext* context, const rips::Case* request, rips::CaseInfo* reply)
{
RimCase* rimCase = findCase(request->id());
if (rimCase)
{
qint64 caseId = rimCase->caseId();
qint64 caseGroupId = -1;
QString caseName, caseType;
RiaSocketTools::getCaseInfoFromCase(rimCase, caseId, caseName, caseType, caseGroupId);
reply->set_id(caseId);
reply->set_group_id(caseGroupId);
reply->set_name(caseName.toStdString());
reply->set_type(caseType.toStdString());
return Status::OK;
}
return Status(grpc::NOT_FOUND, "No cases found");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Status RiaGrpcProjectInfoService::SelectedCases(ServerContext* context, const rips::Empty* request, rips::CaseInfos* reply)
{
std::vector<RimCase*> cases;
caf::SelectionManager::instance()->objectsByType(&cases);
if (cases.empty())
{
return Status(grpc::NOT_FOUND, "No cases selected");
}
for (RimCase* rimCase : cases)
{
qint64 caseId = rimCase->caseId();
qint64 caseGroupId = -1;
QString caseName, caseType;
RiaSocketTools::getCaseInfoFromCase(rimCase, caseId, caseName, caseType, caseGroupId);
rips::CaseInfo* caseInfo = reply->add_case_info();
caseInfo->set_id(caseId);
caseInfo->set_group_id(caseGroupId);
caseInfo->set_name(caseName.toStdString());
caseInfo->set_type(caseType.toStdString());
}
return Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status
RiaGrpcProjectInfoService::AllCaseGroups(grpc::ServerContext* context, const rips::Empty* request, rips::CaseGroups* reply)
{
RimProject* proj = RiaApplication::instance()->project();
RimEclipseCaseCollection* analysisModels =
(proj && proj->activeOilField()) ? proj->activeOilField()->analysisModels() : nullptr;
if (analysisModels)
{
for (RimIdenticalGridCaseGroup* cg : analysisModels->caseGroups())
{
rips::CaseGroup* caseGroup = reply->add_case_group();
caseGroup->set_id(cg->groupId());
caseGroup->set_name(cg->name().toStdString());
}
return Status::OK;
}
return Status(grpc::NOT_FOUND, "No case groups found");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcProjectInfoService::AllCases(grpc::ServerContext* context, const rips::Empty* request, rips::CaseInfos* reply)
{
std::vector<RimCase*> cases;
RiaApplication::instance()->project()->allCases(cases);
if (cases.empty())
{
return Status(grpc::NOT_FOUND, "No cases found");
}
for (RimCase* rimCase : cases)
{
qint64 caseId = rimCase->caseId();
qint64 caseGroupId = -1;
QString caseName, caseType;
RiaSocketTools::getCaseInfoFromCase(rimCase, caseId, caseName, caseType, caseGroupId);
rips::CaseInfo* caseInfo = reply->add_case_info();
caseInfo->set_id(caseId);
caseInfo->set_group_id(caseGroupId);
caseInfo->set_name(caseName.toStdString());
caseInfo->set_type(caseType.toStdString());
}
return Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status
RiaGrpcProjectInfoService::CasesInGroup(grpc::ServerContext* context, const rips::CaseGroup* request, rips::CaseInfos* reply)
{
RimProject* proj = RiaApplication::instance()->project();
RimEclipseCaseCollection* analysisModels =
(proj && proj->activeOilField()) ? proj->activeOilField()->analysisModels() : nullptr;
if (analysisModels)
{
int groupId = request->id();
RimIdenticalGridCaseGroup* caseGroup = nullptr;
for (size_t i = 0; i < analysisModels->caseGroups().size(); i++)
{
RimIdenticalGridCaseGroup* cg = analysisModels->caseGroups()[i];
if (groupId == cg->groupId())
{
caseGroup = cg;
}
}
std::vector<RimCase*> cases;
if (caseGroup)
{
for (size_t i = 0; i < caseGroup->statisticsCaseCollection()->reservoirs.size(); i++)
{
cases.push_back(caseGroup->statisticsCaseCollection()->reservoirs[i]);
}
for (size_t i = 0; i < caseGroup->caseCollection()->reservoirs.size(); i++)
{
cases.push_back(caseGroup->caseCollection()->reservoirs[i]);
}
}
if (!cases.empty())
{
for (RimCase* rimCase : cases)
{
qint64 caseId = rimCase->caseId();
qint64 caseGroupId = -1;
QString caseName, caseType;
RiaSocketTools::getCaseInfoFromCase(rimCase, caseId, caseName, caseType, caseGroupId);
rips::CaseInfo* caseInfo = reply->add_case_info();
caseInfo->set_id(caseId);
caseInfo->set_group_id(caseGroupId);
caseInfo->set_name(caseName.toStdString());
caseInfo->set_type(caseType.toStdString());
}
}
}
return Status(grpc::NOT_FOUND, "No cases found");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RiaAbstractGrpcCallback*> RiaGrpcProjectInfoService::createCallbacks()
{
typedef RiaGrpcProjectInfoService Self;
return {
new RiaGrpcCallback<Self, Empty, Case>(this, &Self::CurrentCase, &Self::RequestCurrentCase),
new RiaGrpcCallback<Self, Empty, CaseInfo>(this, &Self::CurrentCaseInfo, &Self::RequestCurrentCaseInfo),
new RiaGrpcCallback<Self, Case, CaseInfo>(this, &Self::CaseInfoFromCase, &Self::RequestCaseInfoFromCase),
new RiaGrpcCallback<Self, Empty, CaseInfos>(this, &Self::SelectedCases, &Self::RequestSelectedCases),
new RiaGrpcCallback<Self, Empty, CaseGroups>(this, &Self::AllCaseGroups, &Self::RequestAllCaseGroups),
new RiaGrpcCallback<Self, Empty, CaseInfos>(this, &Self::AllCases, &Self::RequestAllCases),
new RiaGrpcCallback<Self, CaseGroup, CaseInfos>(this, &Self::CasesInGroup, &Self::RequestCasesInGroup)};
}
static bool RiaGrpcProjectInfoService_init =
RiaGrpcServiceFactory::instance()->registerCreator<RiaGrpcProjectInfoService>(typeid(RiaGrpcProjectInfoService).hash_code());

View File

@ -0,0 +1,51 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "ProjectInfo.grpc.pb.h"
#include "RiaGrpcServiceInterface.h"
#include <grpcpp/grpcpp.h>
namespace rips
{
class Empty;
class CaseInfo;
} // namespace rips
class RiaAbstractGrpcCallback;
//==================================================================================================
//
// gRPC-service answering requests about project information
//
//==================================================================================================
class RiaGrpcProjectInfoService final : public rips::ProjectInfo::AsyncService, public RiaGrpcServiceInterface
{
public:
grpc::Status CurrentCase(grpc::ServerContext* context, const rips::Empty* request, rips::Case* reply) override;
grpc::Status CurrentCaseInfo(grpc::ServerContext* context, const rips::Empty* request, rips::CaseInfo* reply) override;
grpc::Status CaseInfoFromCase(grpc::ServerContext* context, const rips::Case* request, rips::CaseInfo* reply) override;
grpc::Status SelectedCases(grpc::ServerContext* context, const rips::Empty* request, rips::CaseInfos* reply) override;
grpc::Status AllCaseGroups(grpc::ServerContext* context, const rips::Empty* request, rips::CaseGroups* reply) override;
grpc::Status AllCases(grpc::ServerContext* context, const rips::Empty* request, rips::CaseInfos* reply) override;
grpc::Status CasesInGroup(grpc::ServerContext* context, const rips::CaseGroup* request, rips::CaseInfos* reply) override;
public:
std::vector<RiaAbstractGrpcCallback*> createCallbacks() override;
};

View File

@ -0,0 +1,44 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#include "RiaGrpcResInfoService.h"
#include "RiaVersionInfo.h"
#include "RiaGrpcCallbacks.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcResInfoService::GetVersion(grpc::ServerContext* context, const rips::Empty* request, rips::Version* reply)
{
reply->set_major_version(RESINSIGHT_MAJOR_VERSION);
reply->set_minor_version(RESINSIGHT_MINOR_VERSION);
reply->set_patch_version(RESINSIGHT_PATCH_VERSION);
return grpc::Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RiaAbstractGrpcCallback*> RiaGrpcResInfoService::createCallbacks()
{
typedef RiaGrpcResInfoService Self;
return { new RiaGrpcCallback<Self, rips::Empty, rips::Version>(this, &Self::GetVersion, &Self::RequestGetVersion) };
}
static bool RiaGrpcResInfoService_init =
RiaGrpcServiceFactory::instance()->registerCreator<RiaGrpcResInfoService>(typeid(RiaGrpcResInfoService).hash_code());

View File

@ -0,0 +1,50 @@
#pragma once
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RiaGrpcServiceInterface.h"
#include "ResInfo.grpc.pb.h"
#include <grpcpp/grpcpp.h>
#include <vector>
namespace rips
{
class Empty;
class Version;
}
namespace caf
{
class PdmValueField;
}
class RiaAbstractGrpcCallback;
class RiaGrpcResInfoService : public rips::ResInfo::AsyncService, public RiaGrpcServiceInterface
{
public:
grpc::Status GetVersion(grpc::ServerContext* context, const rips::Empty* request, rips::Version* reply) override;
std::vector<RiaAbstractGrpcCallback*> createCallbacks() override;
};

View File

@ -0,0 +1,366 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#include "RiaGrpcServer.h"
#include "RiaApplication.h"
#include "RiaDefines.h"
#include "RiaGrpcCallbacks.h"
#include "RiaGrpcServiceInterface.h"
#include "RiaGrpcGridInfoService.h"
#include "RigCaseCellResultsData.h"
#include "RigMainGrid.h"
#include "RimEclipseCase.h"
#include "RimProject.h"
#include "cafAssert.h"
#include <grpc/support/log.h>
#include <grpcpp/grpcpp.h>
#include <QTcpServer>
using grpc::CompletionQueue;
using grpc::Server;
using grpc::ServerAsyncResponseWriter;
using grpc::ServerBuilder;
using grpc::ServerCompletionQueue;
using grpc::ServerContext;
using grpc::Status;
//==================================================================================================
//
// The GRPC server implementation
//
//==================================================================================================
class RiaGrpcServerImpl
{
public:
RiaGrpcServerImpl(int portNumber);
~RiaGrpcServerImpl();
int portNumber() const;
bool isRunning() const;
void run();
void runInThread();
void initialize();
void processOneRequest();
void quit();
int currentPortNumber;
private:
void waitForNextRequest();
void process(RiaAbstractGrpcCallback* method);
private:
int m_portNumber;
std::unique_ptr<grpc::ServerCompletionQueue> m_completionQueue;
std::unique_ptr<grpc::Server> m_server;
std::list<std::shared_ptr<RiaGrpcServiceInterface>> m_services;
std::list<RiaAbstractGrpcCallback*> m_unprocessedRequests;
std::mutex m_requestMutex;
std::thread m_thread;
};
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaGrpcServerImpl::RiaGrpcServerImpl(int portNumber)
: m_portNumber(portNumber)
{}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaGrpcServerImpl::~RiaGrpcServerImpl()
{
quit();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RiaGrpcServerImpl::portNumber() const
{
return m_portNumber;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RiaGrpcServerImpl::isRunning() const
{
return m_server != nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcServerImpl::run()
{
initialize();
while (true)
{
waitForNextRequest();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcServerImpl::runInThread()
{
initialize();
m_thread = std::thread(&RiaGrpcServerImpl::waitForNextRequest, this);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcServerImpl::initialize()
{
CAF_ASSERT(m_portNumber > 0 && m_portNumber <= (int) std::numeric_limits<quint16>::max());
QString serverAddress = QString("localhost:%1").arg(m_portNumber);
ServerBuilder builder;
builder.AddListeningPort(serverAddress.toStdString(), grpc::InsecureServerCredentials());
for (auto key : RiaGrpcServiceFactory::instance()->allKeys())
{
std::shared_ptr<RiaGrpcServiceInterface> service(RiaGrpcServiceFactory::instance()->create(key));
builder.RegisterService(dynamic_cast<grpc::Service*>(service.get()));
m_services.push_back(service);
}
m_completionQueue = builder.AddCompletionQueue();
m_server = builder.BuildAndStart();
CVF_ASSERT(m_server);
RiaLogging::info(QString("Server listening on %1").arg(serverAddress));
// Spawn new CallData instances to serve new clients.
for (auto service : m_services)
{
for (auto callback : service->createCallbacks())
{
process(callback);
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcServerImpl::processOneRequest()
{
std::lock_guard<std::mutex> requestLock(m_requestMutex);
if (!m_unprocessedRequests.empty())
{
RiaAbstractGrpcCallback* method = m_unprocessedRequests.front();
m_unprocessedRequests.pop_front();
process(method);
}
}
//--------------------------------------------------------------------------------------------------
/// Gracefully shut down the GRPC server. The internal order is important.
//--------------------------------------------------------------------------------------------------
void RiaGrpcServerImpl::quit()
{
if (m_server)
{
RiaLogging::info("Shutting down gRPC server");
// Clear unhandled requests
while (!m_unprocessedRequests.empty())
{
RiaAbstractGrpcCallback* method = m_unprocessedRequests.front();
m_unprocessedRequests.pop_front();
delete method;
}
// Shutdown server and queue
m_server->Shutdown();
m_completionQueue->Shutdown();
// Wait for thread to join after handling the shutdown call
m_thread.join();
// Must destroy server before services
m_server.reset();
m_completionQueue.reset();
// Finally clear services
m_services.clear();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcServerImpl::waitForNextRequest()
{
void* tag;
bool ok = false;
while (m_completionQueue->Next(&tag, &ok))
{
RiaAbstractGrpcCallback* method = static_cast<RiaAbstractGrpcCallback*>(tag);
if (ok)
{
std::lock_guard<std::mutex> requestLock(m_requestMutex);
m_unprocessedRequests.push_back(method);
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcServerImpl::process(RiaAbstractGrpcCallback* method)
{
if (method->callState() == RiaAbstractGrpcCallback::CREATE_HANDLER)
{
RiaLogging::debug(QString("Initialising request handler for: %1").arg(method->name()));
method->createRequestHandler(m_completionQueue.get());
}
else if (method->callState() == RiaAbstractGrpcCallback::INIT_REQUEST)
{
// Perform initialization and immediately process the first request
// The initialization is necessary for streaming services.
RiaLogging::info(QString("Starting handling: %1").arg(method->name()));
method->initRequest();
method->processRequest();
}
else if (method->callState() == RiaAbstractGrpcCallback::PROCESS_REQUEST)
{
method->processRequest();
}
else
{
RiaLogging::info(QString("Finished handling: %1").arg(method->name()));
method->finishRequest();
process(method->createNewFromThis());
delete method;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaGrpcServer::RiaGrpcServer(int portNumber)
{
m_serverImpl = new RiaGrpcServerImpl(portNumber);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaGrpcServer::~RiaGrpcServer()
{
delete m_serverImpl;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RiaGrpcServer::portNumber() const
{
if (m_serverImpl) return m_serverImpl->portNumber();
return 0;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RiaGrpcServer::isRunning() const
{
if (m_serverImpl) return m_serverImpl->isRunning();
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcServer::run()
{
m_serverImpl->run();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcServer::runInThread()
{
m_serverImpl->runInThread();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcServer::initialize()
{
m_serverImpl->initialize();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcServer::processOneRequest()
{
m_serverImpl->processOneRequest();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcServer::quit()
{
if (m_serverImpl)
m_serverImpl->quit();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RiaGrpcServer::findAvailablePortNumber(int defaultPortNumber)
{
int startPort = 50051;
if (defaultPortNumber > 0 && defaultPortNumber < (int)std::numeric_limits<quint16>::max())
{
startPort = defaultPortNumber;
}
int endPort = std::min(startPort + 100, (int)std::numeric_limits<quint16>::max());
QTcpServer serverTest;
quint16 port = static_cast<quint16>(startPort);
for (; port <= static_cast<quint16>(endPort); ++port)
{
if (serverTest.listen(QHostAddress::LocalHost, port))
{
return static_cast<int>(port);
}
}
return -1;
}

View File

@ -0,0 +1,53 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RiaLogging.h"
#include <iostream>
#include <list>
#include <memory>
#include <mutex>
class RiaGrpcServerImpl;
//==================================================================================================
//
// The GRPC server.
//
//==================================================================================================
class RiaGrpcServer
{
public:
RiaGrpcServer(int portNumber);
~RiaGrpcServer();
int portNumber() const;
bool isRunning() const;
void run();
void runInThread();
void processOneRequest();
void quit();
static int findAvailablePortNumber(int defaultPortNumber);
private:
void initialize();
private:
RiaGrpcServerImpl* m_serverImpl;
};

View File

@ -0,0 +1,54 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#include "RiaGrpcServiceInterface.h"
#include "RiaApplication.h"
#include "RimProject.h"
#include "RimCase.h"
#include <grpcpp/grpcpp.h>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimCase* RiaGrpcServiceInterface::findCase(int caseId)
{
std::vector<RimCase*> cases;
RiaApplication::instance()->project()->allCases(cases);
for (RimCase* rimCase : cases)
{
if (caseId == rimCase->caseId())
{
return rimCase;
}
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
/// Find the number of messages that will fit in the given bytes.
/// The default argument is meant to be a sensible size for GRPC.
//--------------------------------------------------------------------------------------------------
size_t RiaGrpcServiceInterface::numberOfMessagesForByteCount(size_t messageSize,
size_t numBytesWantedInPackage /*= 64 * 1024u*/)
{
size_t messageCount = numBytesWantedInPackage / messageSize;
return messageCount;
}

View File

@ -0,0 +1,43 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <grpcpp/grpcpp.h>
#include <vector>
class RiaAbstractGrpcCallback;
class RimCase;
//==================================================================================================
//
// gRPC-service interface which all gRPC-services has to implement
//
//==================================================================================================
class RiaGrpcServiceInterface
{
public:
virtual std::vector<RiaAbstractGrpcCallback*> createCallbacks() = 0;
virtual ~RiaGrpcServiceInterface() = default;
static RimCase* findCase(int caseId);
static size_t numberOfMessagesForByteCount(size_t messageSize, size_t byteCount = 64 * 1024u);
};
#include "cafFactory.h"
typedef caf::Factory<RiaGrpcServiceInterface, size_t> RiaGrpcServiceFactory;

View File

@ -703,7 +703,7 @@ double RigFlowDiagResults::maxAbsPairFlux(int timeStepIndex)
calculateNativeResultsIfNotPreviouslyAttempted(timeStepIndex, RigFlowDiagResultAddress::PHASE_ALL);
double maxFlux = 0.0;
if (timeStepIndex < m_injProdPairFluxCommunicationTimesteps.size())
if ((size_t) timeStepIndex < m_injProdPairFluxCommunicationTimesteps.size())
{
for (const auto& commPair : m_injProdPairFluxCommunicationTimesteps[timeStepIndex][RigFlowDiagResultAddress::PHASE_ALL])
{

View File

@ -456,6 +456,7 @@ namespace caf {
//==================================================================================================
bool ProgressInfoStatic::s_disabled = false;
bool ProgressInfoStatic::s_running = false;
//--------------------------------------------------------------------------------------------------
///
@ -488,7 +489,7 @@ namespace caf {
}
}
}
s_running = true;
maxProgressStack_v.push_back(maxProgressValue);
progressStack_v.push_back(0);
progressSpanStack_v.push_back(1);
@ -610,6 +611,14 @@ namespace caf {
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool ProgressInfoStatic::isRunning()
{
return s_running;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -652,6 +661,7 @@ namespace caf {
{
dialog->reset();
dialog->close();
s_running = false;
}
}
else

View File

@ -85,14 +85,14 @@ public:
static void setProgress(size_t progressValue);
static void incrementProgress();
static void setNextProgressIncrement(size_t nextStepSize);
static bool isRunning();
static void finished();
private:
static bool isUpdatePossible();
private:
friend class ProgressInfoBlocker;
static bool s_running;
static bool s_disabled;
};

View File

@ -0,0 +1,33 @@
########## Windows using vcpkg ###################
1. Clone VCPKG
git clone https://github.com/microsoft/vcpkg.git
4. Install VCPKG from within vcpkg folder:
.\boostrap-vcpkg.sh
5. Perform integrated install (as admin) within vcpkg folder. Not sure if it is necessary.
.\vcpkg integrate install
5. Install GRPC
.\vcpkg install grpc --triplet x64-windows
6. Run cmake with -DCMAKE_TOOLCHAIN_FILE=LOCATION_OF_VCPKG/buildsystems/vcpkg.cmake
This can be set on the configure dialog that comes up when you press configure with a fresh build folder.
7. Enable GRPC by setting RESINSIGHT_ENABLE_GRPC = true
8. Make sure the python executable is found by setting PYTHON_EXECUTABLE=LOCATION_OF_PYTHON.EXE
############ Linux as STANDALONE GPRC (using GRPC_INSTALL_PREFIX=/opt/grpc as an example) ###############
1. Clone grpc
https://github.com/grpc/grpc.git
2. From within grpc folder, check out stable version of grpc and initialise repo:
git checkout v1.20.1
git submodule init
git submodule update
3. Make sure you're building with devtools-3, since you'll be using that for ResInsight too
scl enable devtoolset-3 bash
make prefix=/opt/grpc
sudo make prefix=/opt/grpc install
3. Install protobuf (still within grpc folder)
cd third_party/protobuf
sudo make prefix=/opt/grpc install
4. Install grpcio-tools for Python (this may have to be done as root user):
pip install grpcio-tools
5. Run cmake making sure GRPC_INSTALL_PREFIX is set to /opt/grpc, PYTHON_EXECUTABLE set to a good python 3 and RESINSIGHT_ENABLE_GRPC = true

3
Python/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
__pycache__
.pytest_cache
generated

159
Python/api/ResInsight.py Normal file
View File

@ -0,0 +1,159 @@
from __future__ import print_function
import grpc
import os
import sys
import socket
sys.path.insert(1, os.path.join(sys.path[0], '../generated'))
import Empty_pb2
import CaseInfo_pb2
import CaseInfo_pb2_grpc
import Commands_pb2
import Commands_pb2_grpc
import GridInfo_pb2
import GridInfo_pb2_grpc
import ProjectInfo_pb2
import ProjectInfo_pb2_grpc
import ResInfo_pb2
import ResInfo_pb2_grpc
import RiaVersionInfo
MAX_MESSAGE_LENGTH = 128 * 1024 * 1024
class ResInfo:
def __init__(self, channel):
self.resInfo = ResInfo_pb2_grpc.ResInfoStub(channel)
def versionMessage(self):
return self.resInfo.GetVersion(Empty_pb2.Empty())
def majorVersion(self):
return self.versionMessage().major_version
def minorVersion(self):
return self.versionMessage().minor_version
def patchVersion(self):
return self.versionMessage().patch_version
def versionString(self):
return str(self.majorVersion()) + "." + str(self.minorVersion()) + "." + str(self.patchVersion())
class CommandExecutor:
def __init__(self, channel):
self.commands = Commands_pb2_grpc.CommandsStub(channel)
def execute(self, commandParams):
try:
self.commands.Execute(commandParams)
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
print("Command not found")
else:
print("Other error")
def setTimeStep(self, caseId, timeStep):
return self.execute(Commands_pb2.CommandParams(setTimeStep=Commands_pb2.SetTimeStepParams(caseId=caseId, timeStep=timeStep)))
def setMainWindowSize(self, width, height):
return self.execute(Commands_pb2.CommandParams(setMainWindowSize=Commands_pb2.SetMainWindowSizeParams(width=width, height=height)))
def openProject(self, path):
return self.execute(Commands_pb2.CommandParams(openProject=Commands_pb2.FilePathRequest(path=path)))
def loadCase(self, path):
return self.execute(Commands_pb2.CommandParams(loadCase=Commands_pb2.FilePathRequest(path=path)))
def closeProject(self):
return self.execute(Commands_pb2.CommandParams(closeProject=Empty_pb2.Empty()))
class GridInfo:
def __init__(self, channel):
self.gridInfo = GridInfo_pb2_grpc.GridInfoStub(channel)
def getGridCount(self, caseId=0):
return self.gridInfo.GetGridCount(CaseInfo_pb2.Case(id=caseId)).count
def getGridDimensions(self, caseId=0):
return self.gridInfo.GetGridDimensions(CaseInfo_pb2.Case(id=caseId)).dimensions
def streamActiveCellInfo(self, caseId=0):
return self.gridInfo.StreamActiveCellInfo(CaseInfo_pb2.Case(id=caseId))
class ProjectInfo:
def __init__(self, channel):
self.projectInfo = ProjectInfo_pb2_grpc.ProjectInfoStub(channel)
def selectedCases(self):
selected = self.projectInfo.SelectedCases(Empty_pb2.Empty())
if selected is not None:
return selected.case_info
else:
return None
def allCases(self):
cases = self.projectInfo.AllCases(Empty_pb2.Empty())
if cases is not None:
return allCases.case_info
else:
return None
class Instance:
@staticmethod
def is_port_in_use(port):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.2)
return s.connect_ex(('localhost', port)) == 0
@staticmethod
def launch():
port = 50051
portEnv = os.environ.get('RESINSIGHT_GRPC_PORT')
if portEnv:
port = int(portEnv)
resInsightExecutable = os.environ.get('RESINSIGHT_EXECUTABLE')
if resInsightExecutable is None:
print('Error: Could not launch any ResInsight instances because RESINSIGHT_EXECUTABLE is not set')
return None
while Instance.is_port_in_use(port):
port += 1
print('Port ' + str(port))
print('Trying to launch', resInsightExecutable)
pid = os.spawnl(os.P_NOWAIT, resInsightExecutable, " --grpcserver " + str(port))
print(pid)
return Instance(port)
@staticmethod
def find(startPort = 50051, endPort = 50071):
portEnv = os.environ.get('RESINSIGHT_GRPC_PORT')
if portEnv:
startPort = int(portEnv)
endPort = startPort + 20
for tryPort in range(startPort, endPort):
if Instance.is_port_in_use(tryPort):
return Instance(tryPort)
print('Error: Could not find any ResInsight instances responding between ports ' + str(startPort) + ' and ' + str(endPort))
return None
def __init__(self, port = 50051):
location = "localhost:" + str(port)
self.channel = grpc.insecure_channel(location, options=[('grpc.max_receive_message_length', MAX_MESSAGE_LENGTH)])
# Main version check package
self.resInfo = ResInfo(self.channel)
try:
majorVersionOk = self.resInfo.majorVersion() == int(RiaVersionInfo.RESINSIGHT_MAJOR_VERSION)
minorVersionOk = self.resInfo.minorVersion() == int(RiaVersionInfo.RESINSIGHT_MINOR_VERSION)
if not (majorVersionOk and minorVersionOk):
raise Exception('Version of ResInsight does not match version of Python API')
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.UNAVAILABLE:
print('Info: Could not find any instances at port ' + str(port))
except Exception as e:
print('Error:', e)
# Service packages
self.commands = CommandExecutor(self.channel)
self.gridInfo = GridInfo(self.channel)
self.projectInfo = ProjectInfo(self.channel)

0
Python/api/__init__.py Normal file
View File

View File

@ -0,0 +1,13 @@
import sys
import os
sys.path.insert(1, os.path.join(sys.path[0], '../api'))
import ResInsight
resInsight = ResInsight.Instance.find()
if resInsight is not None:
caseInfos = resInsight.projectInfo.allCases()
print ("Got " + str(len(caseInfos)) + " cases: ")
for caseInfo in caseInfos:
print(caseInfo.name)

View File

@ -0,0 +1,11 @@
import sys
import os
sys.path.insert(1, os.path.join(sys.path[0], '../api'))
import ResInsight
# Load instance
resInsight = ResInsight.Instance.find()
# Run a couple of commands
resInsight.commands.setTimeStep(caseId=0, timeStep=3)
resInsight.commands.setMainWindowSize(width=800, height=500)

View File

@ -0,0 +1,21 @@
import sys
import os
sys.path.insert(1, os.path.join(sys.path[0], '../api'))
import ResInsight
resInsight = ResInsight.Instance.find()
#gridCount = resInsight.gridInfo.getGridCount(caseId=0)
#gridDimensions = resInsight.gridInfo.getAllGridDimensions(caseId=0)
activeCellInfoChunks = resInsight.gridInfo.streamActiveCellInfo(caseId=0)
#print("Number of grids: " + str(gridCount))
#print(gridDimensions)
receivedActiveCells = []
for activeCellChunk in activeCellInfoChunks:
for activeCell in activeCellChunk.data:
receivedActiveCells.append(activeCell)
print("Number of active cells: " + str(len(receivedActiveCells)))
print("First active cell: ")
print(receivedActiveCells[0])

View File

@ -0,0 +1,45 @@
from ResInsight import ResInsight
import grpc
import logging
import sys
def run():
# NOTE(gRPC Python Team): .close() is possible on a channel and should be
# used in circumstances in which the with statement does not fit the needs
# of the code.
logging.basicConfig()
try:
port = 50051
if len(sys.argv) > 1:
port = sys.argv[1]
resInsight = ResInsight("localhost:" + port)
timeStepsInfo = resInsight.grid.numberOfTimeSteps(ResInsight.Case(id=0))
print ("Number of time steps: " + str(timeStepsInfo.value))
resultsAllTimeSteps = []
for timeStep in range(0, timeStepsInfo.value - 1):
results = resInsight.grid.results(ResInsight.ResultRequest(ResInsight.Case(id=0), ResInsight.ResultAddress(0, "SOIL"), timeStep))
print ("Got " + str(len(results.value)) + " values")
resultsAllTimeSteps.append(results.value)
print("Have stored results array containing " + str(len(resultsAllTimeSteps)) + " time steps")
print("Looking for first cell with a decent SOIL value")
indexFirstProperCell = 0
for i in range(0, len(resultsAllTimeSteps[0])):
result = resultsAllTimeSteps[0][i]
if indexFirstProperCell == 0 and result > 0.01:
indexFirstProperCell = i
for resultsForTimeStep in resultsAllTimeSteps:
print ("Result for cell " + str(indexFirstProperCell) + ": " + str(resultsForTimeStep[indexFirstProperCell]))
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
print("Case id not found")
else:
logging.error('Other error: %s', e)
if __name__ == '__main__':
run()

View File

@ -0,0 +1,14 @@
import sys
import os
sys.path.insert(1, os.path.join(sys.path[0], '../api'))
import ResInsight
resInsight = ResInsight.Instance.find()
if resInsight is not None:
caseInfos = resInsight.projectInfo.selectedCases()
print ("Got " + str(len(caseInfos)) + " cases: ")
for caseInfo in caseInfos:
print(caseInfo.name)

View File

@ -0,0 +1,51 @@
import os, sys
# Add the 'api' path to system path to be able to import modules from the 'api' folder
# python current working directory must be 'tests'
sys.path.insert(1, os.path.join(sys.path[0], '..\\api'))
import ResInsight
resInsight = ResInsight.Instance()
# content of test_sample.py
def getActiveCellCount(caseId):
activeCellInfoChunks = resInsight.gridInfo.streamActiveCellInfo(caseId)
receivedActiveCells = []
for activeCellChunk in activeCellInfoChunks:
for activeCell in activeCellChunk.data:
receivedActiveCells.append(activeCell)
return len(receivedActiveCells)
def myOpenProject(filepath):
resInsight = ResInsight.Instance()
#resInsight.commands.setMainWindowSize(width=800, height=500)
resInsight.commands.openProject(filepath)
def test_openProjectAndCountCells():
testRepositoryRoot = "d:\\gitroot-ceesol\\ResInsight-regression-test"
#casePath = testRepositoryRoot + "\\ModelData\\TEST10K_FLT_LGR_NNC\\TEST10K_FLT_LGR_NNC.EGRID"
#openEclipseCase(casePath)
# projectPath = testRepositoryRoot + "\\ProjectFiles\\ProjectFilesSmallTests\\TestCase_10K_Complete\\RegressionTest.rsp"
# projectPath = testRepositoryRoot + "\\ProjectFiles\\ProjectFilesSmallTests\\TestCase_Norne\\RegressionTest.rsp"
projectPath = testRepositoryRoot + "\\ProjectFiles\\ProjectFilesSmallTests\\TestCase_10K_Watertight\\RegressionTest.rsp"
myOpenProject(projectPath)
assert getActiveCellCount(0) == 11125
def test_openCaseAndCountCells():
testRepositoryRoot = "d:\\gitroot-ceesol\\ResInsight-regression-test"
casePath = testRepositoryRoot + "\\ModelData\\TEST10K_FLT_LGR_NNC\\TEST10K_FLT_LGR_NNC.EGRID"
resInsight.commands.loadCase(casePath)
assert getActiveCellCount(0) == 11125
resInsight.commands.closeProject()