Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
[submodule "jsoncpp"]
path = jsoncpp
url = https://github.com/open-source-parsers/jsoncpp.git
[submodule "python/input_methods/rime/brise"]
path = python/input_methods/rime/brise
url = https://github.com/rime/brise.git
Expand Down
7 changes: 0 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ add_definitions(

add_subdirectory(${PROJECT_SOURCE_DIR}/libIME2)

# turn of some unnecessary build options for jsoncpp
# Reference: http://stackoverflow.com/questions/3766740/overriding-a-default-option-value-in-cmake-from-a-parent-cmakelists-txt
set(JSONCPP_WITH_TESTS OFF CACHE BOOL "")
set(JSONCPP_WITH_POST_BUILD_UNITTEST OFF CACHE BOOL "")
set(JSONCPP_WITH_PKGCONFIG_SUPPORT OFF CACHE BOOL "")
add_subdirectory(${PROJECT_SOURCE_DIR}/jsoncpp)

add_subdirectory(${PROJECT_SOURCE_DIR}/PIMETextService)

# only build the following components for 32-bit x86 platform
Expand Down
37 changes: 19 additions & 18 deletions PIMELauncher/BackendServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,47 +34,48 @@
#include <locale> // for wstring_convert
#include <sstream>

#include <json/json.h>
#include <nlohmann/json.hpp>

#include "BackendServer.h"
#include "PipeServer.h"
#include "PipeClient.h"

using namespace std;
using json = nlohmann::json;

namespace PIME {

static wstring_convert<codecvt_utf8<wchar_t>> utf8Codec;
static constexpr auto MAX_RESPONSE_WAITING_TIME = 30; // if a backend is non-responsive for 30 seconds, it's considered dead

static std::string getUtf8CurrentDir() {
char dirPath[MAX_PATH];
size_t len = MAX_PATH;
uv_cwd(dirPath, &len);
return dirPath;
char dirPath[MAX_PATH];
size_t len = MAX_PATH;
uv_cwd(dirPath, &len);
return dirPath;
}

static std::vector<std::string> getUtf8EnvironmentVariables() {
// build our own new environments
auto env_strs = GetEnvironmentStringsW();
vector<string> utf8Environ;
for (auto penv = env_strs; *penv; penv += wcslen(penv) + 1) {
utf8Environ.emplace_back(utf8Codec.to_bytes(penv));
}
FreeEnvironmentStringsW(env_strs);
return utf8Environ;
// build our own new environments
auto env_strs = GetEnvironmentStringsW();
vector<string> utf8Environ;
for (auto penv = env_strs; *penv; penv += wcslen(penv) + 1) {
utf8Environ.emplace_back(utf8Codec.to_bytes(penv));
}
FreeEnvironmentStringsW(env_strs);
return utf8Environ;
}

BackendServer::BackendServer(PipeServer* pipeServer, const Json::Value& info) :
BackendServer::BackendServer(PipeServer* pipeServer, const json& info) :
pipeServer_{pipeServer},
process_{ nullptr },
stdinPipe_{nullptr},
stdoutPipe_{nullptr},
stderrPipe_{nullptr},
name_(info["name"].asString()),
command_(info["command"].asString()),
workingDir_(info["workingDir"].asString()),
params_(info["params"].asString()) {
name_(info.value("name", "")),
command_(info.value("command", "")),
workingDir_(info.value("workingDir", "")),
params_(info.value("params", "")) {
}

BackendServer::~BackendServer() {
Expand Down
4 changes: 2 additions & 2 deletions PIMELauncher/BackendServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#include <sstream>
#include <memory>

#include <json/json.h>
#include <nlohmann/json.hpp>
#include <spdlog/spdlog.h>

#include "UvPipe.h"
Expand All @@ -45,7 +45,7 @@ class BackendServer {
public:
friend class PipeServer;

BackendServer(PipeServer* pipeServer, const Json::Value& info);
BackendServer(PipeServer* pipeServer, const nlohmann::json& info);

~BackendServer();

Expand Down
2 changes: 1 addition & 1 deletion PIMELauncher/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ add_definitions(

include_directories(
${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/json/single_include
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${LIBUV_INCLUDE_DIRS}
Expand All @@ -48,7 +49,6 @@ add_executable(PIMELauncher WIN32
)

target_link_libraries(PIMELauncher
jsoncpp_lib_static
Rpcrt4 # for uuid stuff
libuv
)
108 changes: 54 additions & 54 deletions PIMELauncher/PipeClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,73 +34,73 @@ static constexpr std::uint64_t BACKEND_REQUEST_TIMEOUT_MS = 30 * 1000;


PipeClient::PipeClient(PipeServer* server, DWORD pipeMode, SECURITY_ATTRIBUTES* securityAttributes) :
server_{ server },
backend_(nullptr),
// generate a new uuid for client ID
clientId_{ generateUuidStr() },
pipe_{ pipeMode, securityAttributes },
waitResponseTimer_{ std::make_unique<uv_timer_t>() } {

pipe_.setBlocking(false);

pipe_.setReadCallback(
[this](const char* data, size_t len) {
handleClientMessage(data, len);
}
);
pipe_.setReadErrorCallback(
[this](int status) {
onReadError(status);
}
);
pipe_.setCloseCallback(
[this]() {
server_->removeClient(this);
}
);

// setup a timer to detect request timeout
server_{ server },
backend_(nullptr),
// generate a new uuid for client ID
clientId_{ generateUuidStr() },
pipe_{ pipeMode, securityAttributes },
waitResponseTimer_{ std::make_unique<uv_timer_t>() } {

pipe_.setBlocking(false);

pipe_.setReadCallback(
[this](const char* data, size_t len) {
handleClientMessage(data, len);
}
);
pipe_.setReadErrorCallback(
[this](int status) {
onReadError(status);
}
);
pipe_.setCloseCallback(
[this]() {
server_->removeClient(this);
}
);

// setup a timer to detect request timeout
uv_timer_init(uv_default_loop(), waitResponseTimer_.get());
waitResponseTimer_->data = this;
}

PipeClient::~PipeClient() {
stopRequestTimeoutTimer();

// Close the uv timer and free its resources.
// NOTE: The operation is async and it's not safe to free the memory here.
// We release the ownership to the unique_ptr and delete the raw pointer in the callback of uv_close().
waitResponseTimer_->data = nullptr; // Avoid referencing to this since this object is destructing.
uv_close(reinterpret_cast<uv_handle_t*>(waitResponseTimer_.release()), [](uv_handle_t* handle) {
delete reinterpret_cast<uv_timer_t*>(handle);
}
);
stopRequestTimeoutTimer();

// Close the uv timer and free its resources.
// NOTE: The operation is async and it's not safe to free the memory here.
// We release the ownership to the unique_ptr and delete the raw pointer in the callback of uv_close().
waitResponseTimer_->data = nullptr; // Avoid referencing to this since this object is destructing.
uv_close(reinterpret_cast<uv_handle_t*>(waitResponseTimer_.release()), [](uv_handle_t* handle) {
delete reinterpret_cast<uv_timer_t*>(handle);
});
}

std::shared_ptr<spdlog::logger>& PipeClient::logger() {
return server_->logger();
}

void PipeClient::close() {
pipe_.close();
pipe_.close();
}

void PipeClient::onReadError(int error) {
// the client connection seems to be broken. close it.
disconnectFromBackend();
close();
// the client connection seems to be broken. close it.
disconnectFromBackend();
close();
}

void PipeClient::handleClientMessage(const char* readBuf, size_t len) {
// NOTE: readBuf is not null terminated.
// NOTE: readBuf is not null terminated.
if (!backend_) {
// special handling, asked for init PIMELauncher.
// extract backend info from the request message and find a suitable backend
Json::Value msg;
Json::Reader reader;
if (reader.parse(readBuf, readBuf + len, msg)) {
try {
nlohmann::json msg = nlohmann::json::parse(std::string(readBuf, len));
initBackend(msg);
}
catch (...) {
}
}

// pass the incoming message to the backend
Expand All @@ -111,12 +111,12 @@ void PipeClient::handleClientMessage(const char* readBuf, size_t len) {
}
}

bool PipeClient::initBackend(const Json::Value & params) {
const char* method = params["method"].asCString();
if (method != nullptr && strcmp(method, "init") == 0) { // the client connects to us the first time
bool PipeClient::initBackend(const nlohmann::json & params) {
std::string method = params.value("method", "");
if (!method.empty() && method == "init") { // the client connects to us the first time
// find a backend for the client text service
const char* guid = params["id"].asCString();
backend_ = server_->backendFromLangProfileGuid(guid);
std::string guid = params.value("id", "");
backend_ = server_->backendFromLangProfileGuid(guid.c_str());
if (backend_ != nullptr) {
// FIXME: write some response to indicate the failure
return true;
Expand All @@ -138,10 +138,10 @@ void PipeClient::disconnectFromBackend() {

void PipeClient::startRequestTimeoutTimer(std::uint64_t timeoutMs) {
uv_timer_start(waitResponseTimer_.get(), [](uv_timer_t* handle) {
if (handle->data) {
auto pThis = reinterpret_cast<PipeClient*>(handle->data);
pThis->onRequestTimeout();
}
if (handle->data) {
auto pThis = reinterpret_cast<PipeClient*>(handle->data);
pThis->onRequestTimeout();
}
}, timeoutMs, 0);
}

Expand All @@ -157,7 +157,7 @@ void PipeClient::onRequestTimeout() {
backend_->restartProcess();
}

// FIXME: do we need to close the pipe or write some error response?
// FIXME: do we need to close the pipe or write some error response?
}

} // namespace PIME
3 changes: 2 additions & 1 deletion PIMELauncher/PipeClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include <spdlog/spdlog.h>

#include <nlohmann/json.hpp>
#include <UvPipe.h>


Expand Down Expand Up @@ -61,7 +62,7 @@ class PipeClient {
pipe_.write(data, len);
}

bool initBackend(const Json::Value& params);
bool initBackend(const nlohmann::json& params);

void disconnectFromBackend();

Expand Down
19 changes: 10 additions & 9 deletions PIMELauncher/PipeServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
#include <locale> // for wstring_convert
#include <sstream>

#include <json/json.h>
#include <nlohmann/json.hpp>
#include <uv.h>

#include <spdlog/spdlog.h>
Expand All @@ -49,6 +49,7 @@
#include "Utils.h"

using namespace std;
using json = nlohmann::json;

namespace PIME {

Expand Down Expand Up @@ -118,16 +119,16 @@ void PipeServer::initLogger() {

void PipeServer::loadConfig() {
auto configFile = dataDirPath_ + CONFIG_FILE_REL_PATH;
Json::Value config;
json config;
if (loadJsonFile(configFile, config)) {
auto levelName = config["logLevel"].asString();
auto levelName = config.value("logLevel", "");
logLevel_ = spdlog::level::from_str(levelName);
}
}

void PipeServer::saveConfig() {
auto configFile = dataDirPath_ + CONFIG_FILE_REL_PATH;
Json::Value config;
json config;
config["logLevel"] = spdlog::level::to_c_str(logLevel_);
if (!saveJsonFile(configFile, config)) {
logger_->error("fail to write config file");
Expand All @@ -136,8 +137,8 @@ void PipeServer::saveConfig() {

void PipeServer::initBackendServers(const std::wstring & topDirPath) {
// load known backend implementations
Json::Value backends;
if (loadJsonFile(topDirPath + L"\\backends.json", backends) && backends.isArray()) {
json backends;
if (loadJsonFile(topDirPath + L"\\backends.json", backends) && backends.is_array()) {
for(auto& backendInfo: backends) {
backends_.emplace_back(
std::make_unique<BackendServer>(this, backendInfo)
Expand Down Expand Up @@ -171,9 +172,9 @@ void PipeServer::initInputMethods(const std::wstring& topDirPath) {
DWORD fileAttrib = GetFileAttributesW(imejson.c_str());
if (fileAttrib != INVALID_FILE_ATTRIBUTES) {
// load the json file to get the info of input method
Json::Value json;
if (loadJsonFile(imejson, json)) {
std::string guid = json["guid"].asString();
json j;
if (loadJsonFile(imejson, j)) {
std::string guid = j.value("guid", "");
transform(guid.begin(), guid.end(), guid.begin(), tolower); // convert GUID to lwoer case
// map text service GUID to its backend server
backendMap_.insert(std::make_pair(guid, backendFromName(backend->name_.c_str())));
Expand Down
Loading
Loading