2017-03-02 09:28:07 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <chrono>
|
|
|
|
#include <string>
|
|
|
|
#include <thread>
|
2017-03-03 08:12:11 +00:00
|
|
|
#include <unordered_map>
|
2017-03-02 09:28:07 +00:00
|
|
|
|
|
|
|
#include <rapidjson/document.h>
|
|
|
|
#include <rapidjson/prettywriter.h>
|
|
|
|
|
|
|
|
#include "platform.h"
|
|
|
|
#include "serializer.h"
|
|
|
|
|
2017-03-05 19:48:05 +00:00
|
|
|
// TODO: We need to add support for payloads larger than the maximum shared memory buffer size.
|
2017-03-02 09:28:07 +00:00
|
|
|
|
|
|
|
|
2017-03-12 00:36:00 +00:00
|
|
|
enum class IpcId : int {
|
|
|
|
// Invalid request id.
|
|
|
|
Invalid = 0,
|
|
|
|
|
|
|
|
Quit = 1,
|
|
|
|
IsAlive,
|
|
|
|
OpenProject,
|
|
|
|
|
|
|
|
// This is a language server request. The actual request method
|
|
|
|
// id is embedded within the request state.
|
|
|
|
LanguageServerRequest,
|
|
|
|
// TODO: remove
|
|
|
|
DocumentSymbolsRequest,
|
|
|
|
DocumentSymbolsResponse,
|
|
|
|
WorkspaceSymbolsRequest,
|
|
|
|
WorkspaceSymbolsResponse
|
2017-03-05 02:16:23 +00:00
|
|
|
};
|
|
|
|
|
2017-03-02 09:28:07 +00:00
|
|
|
|
2017-03-12 00:36:00 +00:00
|
|
|
struct IpcMessage {
|
|
|
|
IpcMessage(IpcId ipc_id) : ipc_id(ipc_id) {}
|
|
|
|
virtual ~IpcMessage() {}
|
2017-03-05 02:16:23 +00:00
|
|
|
|
2017-03-12 00:36:00 +00:00
|
|
|
const IpcId ipc_id;
|
|
|
|
|
|
|
|
virtual void Serialize(Writer& writer) = 0;
|
|
|
|
virtual void Deserialize(Reader& reader) = 0;
|
2017-03-02 09:28:07 +00:00
|
|
|
};
|
|
|
|
|
2017-03-03 08:12:11 +00:00
|
|
|
struct IpcRegistry {
|
2017-03-12 00:36:00 +00:00
|
|
|
using Allocator = std::function<IpcMessage*()>;
|
2017-03-03 08:12:11 +00:00
|
|
|
|
|
|
|
// Use unique_ptrs so we can initialize on first use
|
|
|
|
// (static init order might not be right).
|
2017-03-12 00:36:00 +00:00
|
|
|
std::unique_ptr<std::unordered_map<IpcId, Allocator>> allocators;
|
2017-03-03 08:12:11 +00:00
|
|
|
|
|
|
|
template<typename T>
|
2017-03-12 00:36:00 +00:00
|
|
|
void Register(IpcId id);
|
2017-03-02 09:28:07 +00:00
|
|
|
|
2017-03-12 00:36:00 +00:00
|
|
|
std::unique_ptr<IpcMessage> Allocate(IpcId id);
|
2017-03-02 09:28:07 +00:00
|
|
|
|
2017-03-03 08:12:11 +00:00
|
|
|
static IpcRegistry* instance() {
|
2017-03-03 08:43:54 +00:00
|
|
|
if (!instance_)
|
|
|
|
instance_ = new IpcRegistry();
|
2017-03-03 08:12:11 +00:00
|
|
|
return instance_;
|
|
|
|
}
|
|
|
|
static IpcRegistry* instance_;
|
2017-03-02 09:28:07 +00:00
|
|
|
};
|
|
|
|
|
2017-03-03 08:12:11 +00:00
|
|
|
template<typename T>
|
2017-03-12 00:36:00 +00:00
|
|
|
void IpcRegistry::Register(IpcId id) {
|
|
|
|
if (!allocators)
|
|
|
|
allocators = MakeUnique<std::unordered_map<IpcId, Allocator>>();
|
2017-03-03 08:12:11 +00:00
|
|
|
|
2017-03-12 00:36:00 +00:00
|
|
|
assert(allocators->find(id) == allocators->end() &&
|
|
|
|
"There is already an IPC message with the given id");
|
2017-03-02 09:28:07 +00:00
|
|
|
|
2017-03-12 00:36:00 +00:00
|
|
|
(*allocators)[id] = [id]() {
|
2017-03-03 08:12:11 +00:00
|
|
|
return new T();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-03-03 06:16:28 +00:00
|
|
|
struct IpcDirectionalChannel {
|
2017-03-02 09:28:07 +00:00
|
|
|
// NOTE: We keep all pointers in terms of char* so pointer arithmetic is
|
|
|
|
// always relative to bytes.
|
|
|
|
|
2017-03-03 06:16:28 +00:00
|
|
|
explicit IpcDirectionalChannel(const std::string& name);
|
|
|
|
~IpcDirectionalChannel();
|
2017-03-02 09:28:07 +00:00
|
|
|
|
2017-03-12 00:36:00 +00:00
|
|
|
void PushMessage(IpcMessage* message);
|
|
|
|
std::vector<std::unique_ptr<IpcMessage>> TakeMessages();
|
2017-03-02 09:28:07 +00:00
|
|
|
|
2017-03-13 06:03:54 +00:00
|
|
|
struct MessageBuffer;
|
2017-03-12 20:28:19 +00:00
|
|
|
|
|
|
|
|
2017-03-02 09:28:07 +00:00
|
|
|
// Pointer to process shared memory and process shared mutex.
|
|
|
|
std::unique_ptr<PlatformSharedMemory> shared;
|
|
|
|
std::unique_ptr<PlatformMutex> mutex;
|
|
|
|
|
|
|
|
// Pointer to process-local memory.
|
2017-03-13 06:03:54 +00:00
|
|
|
std::unique_ptr<char> local;
|
2017-03-12 20:28:19 +00:00
|
|
|
|
|
|
|
std::unique_ptr<MessageBuffer> shared_buffer;
|
|
|
|
std::unique_ptr<MessageBuffer> local_buffer;
|
2017-03-03 06:16:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct IpcServer {
|
|
|
|
IpcServer(const std::string& name);
|
|
|
|
|
2017-03-12 00:36:00 +00:00
|
|
|
void SendToClient(int client_id, IpcMessage* message);
|
|
|
|
std::vector<std::unique_ptr<IpcMessage>> TakeMessages();
|
2017-03-03 06:16:28 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
std::string name_;
|
|
|
|
IpcDirectionalChannel server_;
|
|
|
|
std::unordered_map<int, std::unique_ptr<IpcDirectionalChannel>> clients_;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct IpcClient {
|
|
|
|
IpcClient(const std::string& name, int client_id);
|
|
|
|
|
2017-03-12 00:36:00 +00:00
|
|
|
void SendToServer(IpcMessage* message);
|
|
|
|
std::vector<std::unique_ptr<IpcMessage>> TakeMessages();
|
2017-03-03 06:16:28 +00:00
|
|
|
|
2017-03-05 19:48:05 +00:00
|
|
|
IpcDirectionalChannel* client() { return &client_; }
|
|
|
|
|
2017-03-03 06:16:28 +00:00
|
|
|
private:
|
|
|
|
IpcDirectionalChannel server_;
|
|
|
|
IpcDirectionalChannel client_;
|
2017-03-12 00:36:00 +00:00
|
|
|
};
|