diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst index 00ffcd130..61d6896cd 100644 --- a/Help/manual/cmake-server.7.rst +++ b/Help/manual/cmake-server.7.rst @@ -186,6 +186,14 @@ Example:: ]== CMake Server ==] +Type "signal" +^^^^^^^^^^^^^ + +The server can send signals when it detects changes in the system state. Signals +are of type "signal", have an empty "cookie" and "inReplyTo" field and always +have a "name" set to show which signal was sent. + + Specific Message Types ---------------------- diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx index 56cd7ba53..d5dac4e47 100644 --- a/Source/cmServer.cxx +++ b/Source/cmServer.cxx @@ -14,6 +14,7 @@ #include "cmServer.h" #include "cmServerConnection.h" +#include "cmServerDictionary.h" #include "cmServerProtocol.h" #include "cmSystemTools.h" #include "cmVersionMacros.h" @@ -28,19 +29,6 @@ #include #include -static const std::string kTYPE_KEY = "type"; -static const std::string kCOOKIE_KEY = "cookie"; -static const std::string kREPLY_TO_KEY = "inReplyTo"; -static const std::string kERROR_MESSAGE_KEY = "errorMessage"; - -static const std::string kERROR_TYPE = "error"; -static const std::string kREPLY_TYPE = "reply"; -static const std::string kPROGRESS_TYPE = "progress"; -static const std::string kMESSAGE_TYPE = "message"; - -static const std::string kSTART_MAGIC = "[== CMake Server ==["; -static const std::string kEND_MAGIC = "]== CMake Server ==]"; - class cmServer::DebugInfo { public: @@ -144,16 +132,16 @@ void cmServer::PrintHello() const Json::Value hello = Json::objectValue; hello[kTYPE_KEY] = "hello"; - Json::Value& protocolVersions = hello["supportedProtocolVersions"] = + Json::Value& protocolVersions = hello[kSUPPORTED_PROTOCOL_VERSIONS] = Json::arrayValue; for (auto const& proto : this->SupportedProtocols) { auto version = proto->ProtocolVersion(); Json::Value tmp = Json::objectValue; - tmp["major"] = version.first; - tmp["minor"] = version.second; + tmp[kMAJOR_KEY] = version.first; + tmp[kMINOR_KEY] = version.second; if (proto->IsExperimental()) { - tmp["experimental"] = true; + tmp[kIS_EXPERIMENTAL_KEY] = true; } protocolVersions.append(tmp); } @@ -193,31 +181,37 @@ void cmServer::reportMessage(const char* msg, const char* title, cmServerResponse cmServer::SetProtocolVersion(const cmServerRequest& request) { - if (request.Type != "handshake") - return request.ReportError("Waiting for type \"handshake\"."); + if (request.Type != kHANDSHAKE_TYPE) + return request.ReportError("Waiting for type \"" + kHANDSHAKE_TYPE + + "\"."); - Json::Value requestedProtocolVersion = request.Data["protocolVersion"]; + Json::Value requestedProtocolVersion = request.Data[kPROTOCOL_VERSION_KEY]; if (requestedProtocolVersion.isNull()) - return request.ReportError( - "\"protocolVersion\" is required for \"handshake\"."); + return request.ReportError("\"" + kPROTOCOL_VERSION_KEY + + "\" is required for \"" + kHANDSHAKE_TYPE + + "\"."); if (!requestedProtocolVersion.isObject()) - return request.ReportError("\"protocolVersion\" must be a JSON object."); + return request.ReportError("\"" + kPROTOCOL_VERSION_KEY + + "\" must be a JSON object."); - Json::Value majorValue = requestedProtocolVersion["major"]; + Json::Value majorValue = requestedProtocolVersion[kMAJOR_KEY]; if (!majorValue.isInt()) - return request.ReportError("\"major\" must be set and an integer."); + return request.ReportError("\"" + kMAJOR_KEY + + "\" must be set and an integer."); - Json::Value minorValue = requestedProtocolVersion["minor"]; + Json::Value minorValue = requestedProtocolVersion[kMINOR_KEY]; if (!minorValue.isNull() && !minorValue.isInt()) - return request.ReportError("\"minor\" must be unset or an integer."); + return request.ReportError("\"" + kMINOR_KEY + + "\" must be unset or an integer."); const int major = majorValue.asInt(); const int minor = minorValue.isNull() ? -1 : minorValue.asInt(); if (major < 0) - return request.ReportError("\"major\" must be >= 0."); + return request.ReportError("\"" + kMAJOR_KEY + "\" must be >= 0."); if (!minorValue.isNull() && minor < 0) - return request.ReportError("\"minor\" must be >= 0 when set."); + return request.ReportError("\"" + kMINOR_KEY + + "\" must be >= 0 when set."); this->Protocol = this->FindMatchingProtocol(this->SupportedProtocols, major, minor); @@ -226,7 +220,7 @@ cmServerResponse cmServer::SetProtocolVersion(const cmServerRequest& request) } std::string errorMessage; - if (!this->Protocol->Activate(request, &errorMessage)) { + if (!this->Protocol->Activate(this, request, &errorMessage)) { this->Protocol = CM_NULLPTR; return request.ReportError("Failed to activate protocol version: " + errorMessage); @@ -311,10 +305,10 @@ void cmServer::WriteProgress(const cmServerRequest& request, int min, obj[kTYPE_KEY] = kPROGRESS_TYPE; obj[kREPLY_TO_KEY] = request.Type; obj[kCOOKIE_KEY] = request.Cookie; - obj["progressMessage"] = message; - obj["progressMinimum"] = min; - obj["progressMaximum"] = max; - obj["progressCurrent"] = current; + obj[kPROGRESS_MESSAGE_KEY] = message; + obj[kPROGRESS_MINIMUM_KEY] = min; + obj[kPROGRESS_MAXIMUM_KEY] = max; + obj[kPROGRESS_CURRENT_KEY] = current; this->WriteJsonObject(obj, nullptr); } @@ -330,9 +324,9 @@ void cmServer::WriteMessage(const cmServerRequest& request, obj[kTYPE_KEY] = kMESSAGE_TYPE; obj[kREPLY_TO_KEY] = request.Type; obj[kCOOKIE_KEY] = request.Cookie; - obj["message"] = message; + obj[kMESSAGE_KEY] = message; if (!title.empty()) { - obj["title"] = title; + obj[kTITLE_KEY] = title; } WriteJsonObject(obj, nullptr); @@ -349,6 +343,19 @@ void cmServer::WriteParseError(const std::string& message) const this->WriteJsonObject(obj, nullptr); } +void cmServer::WriteSignal(const std::string& name, + const Json::Value& data) const +{ + assert(data.isObject()); + Json::Value obj = data; + obj[kTYPE_KEY] = kSIGNAL_TYPE; + obj[kREPLY_TO_KEY] = ""; + obj[kCOOKIE_KEY] = ""; + obj[kNAME_KEY] = name; + + WriteJsonObject(obj, nullptr); +} + void cmServer::WriteResponse(const cmServerResponse& response, const DebugInfo* debug) const { diff --git a/Source/cmServer.h b/Source/cmServer.h index dde5333ca..849e5c506 100644 --- a/Source/cmServer.h +++ b/Source/cmServer.h @@ -63,6 +63,7 @@ private: void WriteResponse(const cmServerResponse& response, const DebugInfo* debug) const; void WriteParseError(const std::string& message) const; + void WriteSignal(const std::string& name, const Json::Value& obj) const; void WriteJsonObject(Json::Value const& jsonValue, const DebugInfo* debug) const; @@ -95,6 +96,7 @@ private: mutable bool Writing = false; - friend class cmServerRequest; friend class cmServerConnection; + friend class cmServerProtocol; + friend class cmServerRequest; }; diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx index 398e250ec..112cafd7c 100644 --- a/Source/cmServerConnection.cxx +++ b/Source/cmServerConnection.cxx @@ -13,15 +13,14 @@ #include "cmServerConnection.h" +#include "cmServerDictionary.h" + #include #include namespace { -static const std::string kSTART_MAGIC = "[== CMake Server ==["; -static const std::string kEND_MAGIC = "]== CMake Server ==]"; - struct write_req_t { uv_write_t req; diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h new file mode 100644 index 000000000..156ade271 --- /dev/null +++ b/Source/cmServerDictionary.h @@ -0,0 +1,49 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2016 Tobias Hunger + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#pragma once + +#include + +// Vocabulary: + +static const std::string kERROR_TYPE = "error"; +static const std::string kHANDSHAKE_TYPE = "handshake"; +static const std::string kMESSAGE_TYPE = "message"; +static const std::string kPROGRESS_TYPE = "progress"; +static const std::string kREPLY_TYPE = "reply"; +static const std::string kSIGNAL_TYPE = "signal"; + +static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory"; +static const std::string kCOOKIE_KEY = "cookie"; +static const std::string kERROR_MESSAGE_KEY = "errorMessage"; +static const std::string kEXTRA_GENERATOR_KEY = "extraGenerator"; +static const std::string kGENERATOR_KEY = "generator"; +static const std::string kIS_EXPERIMENTAL_KEY = "isExperimental"; +static const std::string kMAJOR_KEY = "major"; +static const std::string kMESSAGE_KEY = "message"; +static const std::string kMINOR_KEY = "minor"; +static const std::string kNAME_KEY = "name"; +static const std::string kPROGRESS_CURRENT_KEY = "progressCurrent"; +static const std::string kPROGRESS_MAXIMUM_KEY = "progressMaximum"; +static const std::string kPROGRESS_MESSAGE_KEY = "progressMessage"; +static const std::string kPROGRESS_MINIMUM_KEY = "progressMinimum"; +static const std::string kPROTOCOL_VERSION_KEY = "protocolVersion"; +static const std::string kREPLY_TO_KEY = "inReplyTo"; +static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory"; +static const std::string kSUPPORTED_PROTOCOL_VERSIONS = + "supportedProtocolVersions"; +static const std::string kTITLE_KEY = "title"; +static const std::string kTYPE_KEY = "type"; + +static const std::string kSTART_MAGIC = "[== CMake Server ==["; +static const std::string kEND_MAGIC = "]== CMake Server ==]"; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index 26942d310..e42b18ae6 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -14,23 +14,17 @@ #include "cmExternalMakefileProjectGenerator.h" #include "cmServer.h" +#include "cmServerDictionary.h" #include "cmSystemTools.h" #include "cmake.h" +#include "cmServerDictionary.h" + #if defined(CMAKE_BUILD_WITH_CMAKE) #include "cm_jsoncpp_reader.h" #include "cm_jsoncpp_value.h" #endif -// Vocabulary: - -static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory"; -static const std::string kCOOKIE_KEY = "cookie"; -static const std::string kEXTRA_GENERATOR_KEY = "extraGenerator"; -static const std::string kGENERATOR_KEY = "generator"; -static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory"; -static const std::string kTYPE_KEY = "type"; - cmServerRequest::cmServerRequest(cmServer* server, const std::string& t, const std::string& c, const Json::Value& d) : Type(t) @@ -115,9 +109,12 @@ Json::Value cmServerResponse::Data() const return this->m_Data; } -bool cmServerProtocol::Activate(const cmServerRequest& request, +bool cmServerProtocol::Activate(cmServer* server, + const cmServerRequest& request, std::string* errorMessage) { + assert(server); + this->m_Server = server; this->m_CMakeInstance = std::make_unique(); const bool result = this->DoActivate(request, errorMessage); if (!result) @@ -125,6 +122,13 @@ bool cmServerProtocol::Activate(const cmServerRequest& request, return result; } +void cmServerProtocol::SendSignal(const std::string& name, + const Json::Value& data) const +{ + if (this->m_Server) + this->m_Server->WriteSignal(name, data); +} + cmake* cmServerProtocol::CMakeInstance() const { return this->m_CMakeInstance.get(); diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h index bab949b75..0383dfe50 100644 --- a/Source/cmServerProtocol.h +++ b/Source/cmServerProtocol.h @@ -87,7 +87,10 @@ public: virtual bool IsExperimental() const = 0; virtual const cmServerResponse Process(const cmServerRequest& request) = 0; - bool Activate(const cmServerRequest& request, std::string* errorMessage); + bool Activate(cmServer* server, const cmServerRequest& request, + std::string* errorMessage); + + void SendSignal(const std::string& name, const Json::Value& data) const; protected: cmake* CMakeInstance() const; @@ -97,6 +100,7 @@ protected: private: std::unique_ptr m_CMakeInstance; + cmServer* m_Server = nullptr; // not owned! friend class cmServer; };