1 /***************************************************************************
2                           rkrbackendprotocol  -  description
3                              -------------------
4     begin                : Thu Nov 04 2010
5     copyright            : (C) 2010-2018 by Thomas Friedrichsmeier
6     email                : thomas.friedrichsmeier@kdemail.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #ifndef RKRBACKENDPROTOCOL_SHARED_H
19 #define RKRBACKENDPROTOCOL_SHARED_H
20 
21 #include <QVariantMap>
22 #include <QMutex>
23 #include "rcommand.h"
24 
25 class RCommandProxy;
26 
27 class RBackendRequest {
28 public:
29 	enum RCallbackType {
30 		BackendExit,
31 		ShowMessage,
32 		ShowFiles,
33 		ChooseFile,
34 		EditFiles,
35 		ReadLine,      // 5
36 		CommandOut,
37 		Started,
38 		EvalRequest,
39 		CallbackRequest,
40 		HistoricalSubstackRequest,   // 10
41 		PlainGenericRequest,
42 		SetParamsFromBackend,
43 		Debugger,
44 		CommandLineIn,	/**< The next line of the current user command has been submitted in the backend. */
45 		Output,		/**< A piece of output. Note: If the backend runs in a single process, output is handled in a pull fashion, instead of using requests. */  //15
46 		Interrupt,	/**< Interrupt evaluation. This request type originates in the frontend, not the backend. */
47 		PriorityCommand, /**< Send a command to be run during R's event processing. This request type originates in the frontend, not the backend. */
48 		OutputStartedNotification, /**< Only used in the frontend: Notification that a new bit of output has arrived. Used to trigger flushing after a timeout. */
49 		OtherRequest		/**< Any other type of request. Note: which requests are in the enum, and which are not has mostly historical reasons. @see params */
50 	};
51 
52 	RBackendRequest (bool synchronous, RCallbackType type);
53 	~RBackendRequest ();
54 
takeCommand()55 	RCommandProxy *takeCommand () {
56 		RCommandProxy* ret = command;
57 		command = 0;
58 		return ret;
59 	}
60 
takeOutput()61 	ROutputList *takeOutput () {
62 		ROutputList* ret = output;
63 		output = 0;
64 		return ret;
65 	}
66 
67 /** Should this request be handled synchronously? False by default. */
68 	bool synchronous;
69 /** For synchronous requests, only: The frontend-thread will set this to true (using completed()), once the request has been "completed". Important: The backend thread MUST NOT touch a request after it has been sent, and before "done" has been set to true. */
70 	bool volatile done;
71 	int id;
72 	static int _id;
73 	RCallbackType type;
74 /** For synchronous requests, only: If the frontend wants any commands to be executed, it will place the next one in this slot. The backend thread should keep executing commands (in a sub-eventloop) while this is non-zero. Also, the backend-thread may place here any command that has just finished. */
75 	RCommandProxy *command;
76 /** Any other parameters, esp. for RCallbackType::OtherRequest. Can be used in both directions. */
77 	QVariantMap params;
78 /** NOTE: only used for separate process backend. See RCallbackType::Output */
79 	ROutputList *output;
80 /** NOTE: this does @em not copy merge the "done" flag. Do that manually, @em after merging (and don't touch the request from the transmitter thread, after that). */
81 	void mergeReply (RBackendRequest *reply);
82 protected:
83 	friend class RKRBackendProtocolFrontend;
84 	friend class RKRBackendProtocolBackend;
85 
completed()86 	void completed () {
87 		if (!synchronous) delete this;
88 		else done = true;
89 	}
90 
91 /** duplicates the request. NOTE: The command, and output, if any are @em taken from the original, and transferred to the copy, not really duplicated. */
92 	RBackendRequest *duplicate ();
93 };
94 
95 #include <QEvent>
96 /** Simple event class to relay information from the RKRBackend to the main thread. This is basically like QCustomEvent in Qt3*/
97 class RKRBackendEvent : public QEvent {
98 public:
99 	enum EventType {
100 		RKWardEvent = QEvent::User + 1
101 	};
102 	explicit RKRBackendEvent (RBackendRequest* data=0) : QEvent ((QEvent::Type) RKWardEvent) { _data = data; };
103 	RKRBackendEvent ();
104 
data()105 	RBackendRequest* data () { return _data; };
106 private:
107 	RBackendRequest* _data;
108 };
109 
110 /** This is a reduced version of an RCommand, intended for use in the R backend. */
111 class RCommandProxy : public RData {
112 protected:
113 friend class RCommand;
114 friend class RKRBackend;
115 friend class RKRBackendSerializer;
116 friend class RBackendRequest;
117 	RCommandProxy ();
118 	~RCommandProxy ();
119 	RCommandProxy (const QString &command, int type);
120 public:		// all these are public for technical reasons, only.
121 	QString command;
122 	int type;
123 	int id;
124 	int status;
125 	int has_been_run_up_to;
126 };
127 
128 class RKROutputBuffer {
129 public:
130 	RKROutputBuffer ();
131 	virtual ~RKROutputBuffer ();
132 
133 /** This gets called on normal R output (R_WriteConsole). Used to get at output.
134     returns true, if a *new* piece of output started, i.e. the buffer was empty before this. */
135 	bool handleOutput (const QString &output, int len, ROutput::ROutputType type, bool allow_blocking=true);
136 
137 	enum CaptureMode {
138 		RecordMessages = 1,
139 		RecordOutput = 2,
140 		SuppressMessages = 4,
141 		SuppressOutput = 8
142 	};
143 	void pushOutputCapture (int capture_mode);
144 	QString popOutputCapture (bool highlighted);
145 
146 /** Flushes current output buffer. Meant to be called from RInterface::flushOutput, only.
147 @param forcibly: if true, will always flush the output. If false, will flush the output only if the mutex can be locked without waiting. */
148 	ROutputList flushOutput (bool forcibly=false);
149 protected:
150 /** Function to be called while waiting for downstream threads to catch up. Return false to make the buffer continue, immediately (e.g. to prevent lockups after a crash) */
151 	virtual bool doMSleep (int msecs) = 0;
152 private:
153 /** current output */
154 	ROutputList output_buffer;
155 /** Provides thread-safety for the output_buffer */
156 	QMutex output_buffer_mutex;
157 /** current length of output. If the backlog of output which has not yet been processed by the frontend becomes too long, output will be paused, automatically */
158 	int out_buf_len;
159 
160 	struct OutputCapture {
161 		ROutputList recorded;
162 		int mode;
163 	};
164 	QList<OutputCapture> output_captures;
165 };
166 
167 namespace RKRSharedFunctionality {
168 	QString quote (const QString &string);
169 };
170 
171 #endif
172