diff --git a/README.md b/README.md index 80c68616..57d22588 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ * Boost 1.59 * Botan 1.11.34 +also something about java, but who knows... + #### Environment Variables * QT_DIR - .../Qt/Qt5.6.0/5.6/ diff --git a/ide_plugins/vs/coati_plugin_vs.vsix b/ide_plugins/vs/coati_plugin_vs.vsix index fa292cf9..2d454877 100644 Binary files a/ide_plugins/vs/coati_plugin_vs.vsix and b/ide_plugins/vs/coati_plugin_vs.vsix differ diff --git a/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/CoatiPlugin.vsct b/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/CoatiPlugin.vsct index a8717fa8..e65e397a 100644 --- a/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/CoatiPlugin.vsct +++ b/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/CoatiPlugin.vsct @@ -66,6 +66,7 @@ --> + + diff --git a/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/CoatiPluginPackage.cs b/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/CoatiPluginPackage.cs index 21248e76..f76d32d0 100644 --- a/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/CoatiPluginPackage.cs +++ b/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/CoatiPluginPackage.cs @@ -198,6 +198,8 @@ namespace CoatiSoftware.CoatiPlugin _solutionEvents.Opened += OnSolutionOpened; _solutionEvents.AfterClosing += OnSolutionClosed; + SendPing(); + Logging.Logging.LogInfo("Initialization done"); } @@ -287,6 +289,13 @@ namespace CoatiSoftware.CoatiPlugin Logging.Logging.LogInfo("Logging initialized"); } + private void SendPing() + { + string message = Utility.NetworkProtocolUtility.CreatePingMessage(); + + Utility.AsynchronousClient.Send(message); + } + private void OnCreateProject(List projects, string configurationName, string platformName, string targetDir, string fileName, string cStandard) { Wizard.WindowCreateCDB createCDB = new Wizard.WindowCreateCDB(); @@ -461,6 +470,10 @@ namespace CoatiSoftware.CoatiPlugin CreateCompilationDatabase(dte); } } + else if(messageType == Utility.NetworkProtocolUtility.MESSAGE_TYPE.PING) + { + SendPing(); + } } private void OnNetworkErrorCallback(string message) diff --git a/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/Utility/NetworkProtocolUtility.cs b/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/Utility/NetworkProtocolUtility.cs index 93a3b277..1d752021 100644 --- a/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/Utility/NetworkProtocolUtility.cs +++ b/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/Utility/NetworkProtocolUtility.cs @@ -13,17 +13,20 @@ namespace CoatiSoftware.CoatiPlugin.Utility private static string s_moveCursorPrefix = "moveCursor"; private static string s_endOfMessageToken = ""; - private static string s_createProjectPrefix = "createProject"; + private static string s_createProjectPrefix = "createProject"; // deprecate private static string s_createCDBProjectPrefix = "createCDBProject"; private static string s_ideId = "vs"; - private static string s_createCDB = "createCDB"; + private static string s_createCDBPrefix = "createCDB"; + + private static string s_pingPrefix = "ping"; public enum MESSAGE_TYPE { UNKNOWN = 0, MOVE_CURSOR, - CREATE_CDB + CREATE_CDB, + PING } public class CursorPosition @@ -58,6 +61,24 @@ namespace CoatiSoftware.CoatiPlugin.Utility } } + public class Ping + { + private string _id = ""; + private bool _valid = false; + + public string Id + { + get { return _id; } + set { _id = value; } + } + + public bool Valid + { + get { return _valid; } + set { _valid = value; } + } + } + public static string CreateActivateTokenMessage(string filePath, int lineNumber, int columnNumber) { string message = s_setActiveTokenPrefix; @@ -120,20 +141,37 @@ namespace CoatiSoftware.CoatiPlugin.Utility return message; } + public static string CreatePingMessage() + { + string message = s_pingPrefix; + + message += s_divider; + + message += s_ideId; + + message += s_endOfMessageToken; + + return message; + } + public static MESSAGE_TYPE GetMessageType(string message) { List tokens = GetMessageTokens(message); if (tokens.Count > 0) { - if(tokens[0] == s_createCDB) + if (tokens[0] == s_createCDBPrefix) { return MESSAGE_TYPE.CREATE_CDB; } - else if(tokens[0] == s_moveCursorPrefix) + else if (tokens[0] == s_moveCursorPrefix) { return MESSAGE_TYPE.MOVE_CURSOR; } + else if (tokens[0] == s_pingPrefix) + { + return MESSAGE_TYPE.PING; + } else { return MESSAGE_TYPE.UNKNOWN; @@ -193,6 +231,32 @@ namespace CoatiSoftware.CoatiPlugin.Utility return result; } + public static Ping ParsePingMessage(string message) + { + Ping result = new Ping(); + + List tokens = GetMessageTokens(message); + + if(tokens.Count != 2) + { + Logging.Logging.LogError("Invalid message: " + message); + Logging.Logging.LogError("Invalid token count for 'ping' message. Expected 2, but got " + tokens.Count.ToString()); + return result; + } + + if (tokens[0] != s_pingPrefix) + { + Logging.Logging.LogError("Invalid message: " + message); + Logging.Logging.LogError("Invalid message type. Expected '" + s_pingPrefix + "' but got '" + tokens[0] + "'"); + return result; + } + + result.Id = tokens[1]; + result.Valid = true; + + return result; + } + private static List GetMessageTokens(string message) { List tokens = new List(); diff --git a/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/source.extension.vsixmanifest b/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/source.extension.vsixmanifest index 23634a66..5e044308 100644 --- a/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/source.extension.vsixmanifest +++ b/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + CoatiPlugin This package allows Coati to communicate with Visual Studio and vice versa. https://www.coati.io/ diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 7858b9e2..4a13bf16 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -276,6 +276,7 @@ add_files( utility/messaging/type/MessageLoadProject.h utility/messaging/type/MessageMoveIDECursor.h utility/messaging/type/MessageNewErrors.h + utility/messaging/type/MessagePingReceived.h utility/messaging/type/MessagePluginPortChange.h utility/messaging/type/MessageProjectEdit.h utility/messaging/type/MessageProjectNew.h diff --git a/src/lib/component/controller/IDECommunicationController.cpp b/src/lib/component/controller/IDECommunicationController.cpp index 61c03c45..5864b96e 100644 --- a/src/lib/component/controller/IDECommunicationController.cpp +++ b/src/lib/component/controller/IDECommunicationController.cpp @@ -12,6 +12,7 @@ #include "utility/messaging/type/MessageProjectNew.h" #include "utility/messaging/type/MessageStatus.h" #include "utility/messaging/type/MessageActivateFile.h" +#include "utility/messaging/type/MessagePingReceived.h" IDECommunicationController::IDECommunicationController(StorageAccess* storageAccess) : m_storageAccess(storageAccess) @@ -48,6 +49,10 @@ void IDECommunicationController::handleIncomingMessage(const std::string& messag { handleCreateCDBProjectMessage(NetworkProtocolHelper::parseCreateCDBProjectMessage(message)); } + else if (type == NetworkProtocolHelper::MESSAGE_TYPE::PING) + { + handlePing(NetworkProtocolHelper::parsePingMessage(message)); + } else { handleCreateProjectMessage(NetworkProtocolHelper::parseCreateProjectMessage(message)); @@ -152,8 +157,6 @@ void IDECommunicationController::handleCreateCDBProjectMessage(const NetworkProt msg->setHeaderPaths(message.headerPaths); msg->ideId = message.ideId; - bool foo = msg->fromCDB(); - MessageDispatchWhenLicenseValid(msg).dispatch(); } else @@ -162,6 +165,32 @@ void IDECommunicationController::handleCreateCDBProjectMessage(const NetworkProt } } +void IDECommunicationController::handlePing(const NetworkProtocolHelper::PingMessage& message) +{ + if (message.valid) + { + std::shared_ptr msg = std::make_shared(); + msg->ideId = message.ideId; + + std::string ideName = "unknown"; + + if (msg->ideId == "vs") + { + ideName = "Visual Studio"; + } + // TODO: add the other ides + + std::string message = ideName + " instance detected"; + + MessageStatus(message, false, false).dispatch(); + MessageDispatchWhenLicenseValid(msg).dispatch(); + } + else + { + LOG_ERROR_STREAM(<< "Can't handle ping, message is invalid"); + } +} + void IDECommunicationController::handleMessage(MessageIDECreateCDB* message) { std::string networkMessage = NetworkProtocolHelper::buildCreateCDBMessage(); diff --git a/src/lib/component/controller/IDECommunicationController.h b/src/lib/component/controller/IDECommunicationController.h index de348226..73301c73 100644 --- a/src/lib/component/controller/IDECommunicationController.h +++ b/src/lib/component/controller/IDECommunicationController.h @@ -38,6 +38,7 @@ private: void handleSetActiveTokenMessage(const NetworkProtocolHelper::SetActiveTokenMessage& message); void handleCreateProjectMessage(const NetworkProtocolHelper::CreateProjectMessage& message); void handleCreateCDBProjectMessage(const NetworkProtocolHelper::CreateCDBProjectMessage& message); + void handlePing(const NetworkProtocolHelper::PingMessage& message); virtual void handleMessage(MessageIDECreateCDB* message); virtual void handleMessage(MessageMoveIDECursor* message); diff --git a/src/lib/component/controller/helper/NetworkProtocolHelper.cpp b/src/lib/component/controller/helper/NetworkProtocolHelper.cpp index 04534212..5f54ccda 100644 --- a/src/lib/component/controller/helper/NetworkProtocolHelper.cpp +++ b/src/lib/component/controller/helper/NetworkProtocolHelper.cpp @@ -14,6 +14,7 @@ std::string NetworkProtocolHelper::m_endOfMessageToken = ""; std::string NetworkProtocolHelper::m_createProjectPrefix = "createProject"; std::string NetworkProtocolHelper::m_createCDBProjectPrefix = "createCDBProject"; std::string NetworkProtocolHelper::m_createCDBPrefix = "createCDB"; +std::string NetworkProtocolHelper::m_pingPrefix = "ping"; NetworkProtocolHelper::MESSAGE_TYPE NetworkProtocolHelper::getMessageType(const std::string& message) { @@ -33,6 +34,10 @@ NetworkProtocolHelper::MESSAGE_TYPE NetworkProtocolHelper::getMessageType(const { return MESSAGE_TYPE::CREATE_CDB_MESSAGE; } + else if (subMessages[0] == m_pingPrefix) + { + return MESSAGE_TYPE::PING; + } else { return MESSAGE_TYPE::UNKNOWN; @@ -196,6 +201,48 @@ NetworkProtocolHelper::CreateCDBProjectMessage NetworkProtocolHelper::parseCreat return networkMessage; } +NetworkProtocolHelper::PingMessage NetworkProtocolHelper::parsePingMessage(const std::string& message) +{ + std::vector subMessages = divideMessage(message); + + NetworkProtocolHelper::PingMessage pingMessage; + + if (subMessages.size() > 0) + { + if (subMessages[0] == m_pingPrefix) + { + if (subMessages.size() < 2) + { + LOG_ERROR_STREAM(<< "Failed to parse PingMessage message, too few tokens"); + } + else + { + std::string ideId = subMessages[1]; + + if (ideId.length() > 0) + { + std::string nonConstId = ideId; + boost::algorithm::to_lower(nonConstId); + + pingMessage.ideId = ideId; + + pingMessage.valid = true; + } + else + { + LOG_WARNING_STREAM(<< "Failed to parse ide ID string. Is " << ideId); + } + } + } + else + { + LOG_ERROR_STREAM(<< "Failed to parse message, invalid type token: " << subMessages[0] << ". Expected " << m_pingPrefix); + } + } + + return pingMessage; +} + std::string NetworkProtocolHelper::buildSetIDECursorMessage(const std::string& fileLocation, const unsigned int row, const unsigned int column) { std::stringstream messageStream; @@ -222,6 +269,18 @@ std::string NetworkProtocolHelper::buildCreateCDBMessage() return messageStream.str(); } +std::string NetworkProtocolHelper::buildPingMessage() +{ + std::stringstream messageStream; + + messageStream << m_pingPrefix; + messageStream << m_divider; + messageStream << "coati"; + messageStream << m_endOfMessageToken; + + return messageStream.str(); +} + std::vector NetworkProtocolHelper::divideMessage(const std::string& message) { std::vector result; diff --git a/src/lib/component/controller/helper/NetworkProtocolHelper.h b/src/lib/component/controller/helper/NetworkProtocolHelper.h index 45d7d7cf..9bc5d740 100644 --- a/src/lib/component/controller/helper/NetworkProtocolHelper.h +++ b/src/lib/component/controller/helper/NetworkProtocolHelper.h @@ -53,12 +53,25 @@ public: bool valid; }; + struct PingMessage + { + public: + PingMessage() + : ideId("") + , valid(false) + {} + + std::string ideId; + bool valid; + }; + enum MESSAGE_TYPE { UNKNOWN = 0, SET_ACTIVE_TOKEN, CREATE_PROJECT, - CREATE_CDB_MESSAGE + CREATE_CDB_MESSAGE, + PING }; static MESSAGE_TYPE getMessageType(const std::string& message); @@ -66,9 +79,11 @@ public: static SetActiveTokenMessage parseSetActiveTokenMessage(const std::string& message); static CreateProjectMessage parseCreateProjectMessage(const std::string& message); static CreateCDBProjectMessage parseCreateCDBProjectMessage(const std::string& message); + static PingMessage parsePingMessage(const std::string& message); static std::string buildSetIDECursorMessage(const std::string& fileLocation, const unsigned int row, const unsigned int column); static std::string buildCreateCDBMessage(); + static std::string buildPingMessage(); private: static std::vector divideMessage(const std::string& message); @@ -85,6 +100,7 @@ private: static std::string m_createProjectPrefix; static std::string m_createCDBProjectPrefix; static std::string m_createCDBPrefix; + static std::string m_pingPrefix; }; #endif // NETWORK_PROTOCOL_HELPER_H \ No newline at end of file diff --git a/src/lib/utility/messaging/type/MessagePingReceived.h b/src/lib/utility/messaging/type/MessagePingReceived.h new file mode 100644 index 00000000..d2c76f4e --- /dev/null +++ b/src/lib/utility/messaging/type/MessagePingReceived.h @@ -0,0 +1,23 @@ +#ifndef MESSAGE_PING_RECEIVED_H +#define MESSAGE_PING_RECEIVED_H + +#include "utility/messaging/Message.h" + +class MessagePingReceived + : public Message +{ +public: + MessagePingReceived() + : ideId("") + { + } + + static const std::string getStaticType() + { + return "MessagePingReceived"; + } + + std::string ideId; +}; + +#endif // MESSAGE_PING_RECEIVED_H \ No newline at end of file diff --git a/web/documentation/index.html b/web/documentation/index.html index 2668963e..1578987d 100644 --- a/web/documentation/index.html +++ b/web/documentation/index.html @@ -1911,6 +1911,64 @@ +

IDE Communication Protocol

+

Coati's IDE plugins communicate with Coati via sockets, using TCP. Coati implements a number of messages to provide an interface for the plugins.

+

This chapter explains the general structure of those messages, followed by a list of possible message types.

+ +

Message Structure

+ +

The basic structure of the messages used by Coati plugins consists of a prefix to identify the message type, followed by no, one, or multiple parameters and ends with an 'end-of-message' token. Parameters and tokens are seperated by a 'divider' token.

+ + + + + + + + + + + +
Name Token Description
messageType see below A string that determines how the message will be interpreted by Coati or the plugin
divider >> Seperates the tokens of the message
parameter see below Typically an integer or string
endOfMessage <EOM> Helps to determine the end of a message
+ +

Messages have the following form:

+ +

messageType<<parameter<<...<<parameter<EOM>

+ +

Message Types

+ +

Coati does implement a number of message types that can be used by Coati plugins. In the following is a list of the messages that Coati may send to plugins and messages that may be sent by a plugin to Coati.

+ +

Note that you can chose which messages you want to implement. Coati will not make problems if you chose to ignore certain messages.

+ + Incoming messages +

These messages may be received by a plugin.

+ + + + + + + + + + +
Message Parameters Description
moveCursor fileLocation: string
row: integer
column: integer
Set the cursor of your editor or IDE to the given file location.
Note that fileLocation is the absolute path and name of the target file.
createCDB Coati may send this message to prompt your plugin to create a Compilation Database (CDB). Once the CDB is ready you may want to respond with a createCDBProject message.
ping Coati may send a ping to determine if anybody is listening. Respond with a ping message yourself. Coati will not respond to this message.
+ + Outgoing messages +

Your plugin may send these messages to Coati.

+ + + + + + + + + + +
Message Parameters Description
setActiveToken fileLocation: string
row: integer
column: integer
Tells Coati to shift focus to the token located at the given position. Note that fileLocation is the absolute path and name of the target file.
createCDBProject cdbPath: string
headerPaths: string
If your plugin can provide a Compilation Database this message can prompt Coati to import it and display an appropriate dialog for the user. headerPaths is a list of the base project's header include paths. Seperate the single paths using the divider token. You can add as many paths as you need.
ping Your plugin may send this message to Coati to tell it it's listening.
+