File: rinsideclient.cpp

package info (click to toggle)
r-cran-rinside 0.2.19-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 668 kB
  • sloc: cpp: 3,310; ansic: 117; xml: 57; ruby: 34; makefile: 2
file content (123 lines) | stat: -rw-r--r-- 3,357 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
 * 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);
}