EVOLUTION-MANAGER
Edit File: rinsideclient.cpp
/* * Copyright (c) 2014 Christian Authmann */ #include "rinsideclient.h" #include "common/constants.h" #include <exception> #include <stdexcept> RInsideClient::RInsideClient(BinaryStream &_stream) : stream(std::move(_stream)), next_callback_id(1), had_unrecoverable_error(false), can_send_command(false) { stream.write(RIS_MAGIC_NUMBER); can_send_command = true; } RInsideClient::~RInsideClient() { if (!had_unrecoverable_error && can_send_command) { try { stream.write(RIS_CMD_EXIT); } catch (...) { // don't ever throw in a destructor! } } } void RInsideClient::runScript(const std::string code, int32_t result_typeid) { writeCommand(RIS_CMD_RUN); stream.write(code); stream.write(result_typeid); while (true) { auto reply = stream.read<char>(); if (reply == RIS_REPLY_CALLBACK) { auto callback_id = stream.read<uint32_t>(); auto &func = callbacks.at(callback_id); try { func(); } catch (const callback_helper::parameter_error_exception &e) { // This is a recoverable error! can_send_command = true; throw std::runtime_error(e.what()); } catch (...) { had_unrecoverable_error = true; throw; } } else if (reply == RIS_REPLY_OK) { if (result_typeid != 0) unrecoverable_error("runScript() did not return a value when one was requested"); return; } else if (reply == RIS_REPLY_VALUE) { if (result_typeid == 0) unrecoverable_error("runScript() did return a value when none was requested"); auto type = stream.read<int32_t>(); if (type != result_typeid) unrecoverable_error("runScript() did return a value of the wrong type"); return; } } } std::string RInsideClient::getConsoleOutput() { writeCommand(RIS_CMD_GETCONSOLE); readReply(false, true); auto result = stream.read<std::string>(); can_send_command = true; return result; } void RInsideClient::initPlot(uint32_t width, uint32_t height) { writeCommand(RIS_CMD_INITPLOT); stream.write(width); stream.write(height); readReply(true, false); can_send_command = true; } std::string RInsideClient::getPlot() { writeCommand(RIS_CMD_GETPLOT); readReply(false, true); auto result = stream.read<std::string>(); can_send_command = true; return result; } void RInsideClient::writeCommand(char command) { if (had_unrecoverable_error) throw std::runtime_error("RInsideClient cannot continue due to previous unrecoverable errors"); if (!can_send_command) throw std::runtime_error("RInsideClient cannot send a command at this time"); stream.write(command); can_send_command = false; } char RInsideClient::readReply(bool accept_ok, bool accept_value) { auto reply = stream.read<char>(); if (reply == RIS_REPLY_ERROR) { auto error = stream.read<std::string>(); can_send_command = true; throw std::runtime_error(std::string("Error in R Server: ") + error); } if (reply == RIS_REPLY_OK && !accept_ok) unrecoverable_error("Got unexpected reply from the R server"); if (reply == RIS_REPLY_VALUE && !accept_value) unrecoverable_error("Got unexpected reply from the R server"); return reply; } void RInsideClient::unrecoverable_error(const std::string &error) { had_unrecoverable_error = true; throw std::runtime_error(error); }