1 /*
2  * RSession.hpp
3  *
4  * Copyright (C) 2021 by RStudio, PBC
5  *
6  * Unless you have received this program directly from RStudio pursuant
7  * to the terms of a commercial license agreement with RStudio, then
8  * this program is licensed to you under the terms of version 3 of the
9  * GNU Affero General Public License. This program is distributed WITHOUT
10  * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
11  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
12  * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
13  *
14  */
15 
16 #ifndef R_RSESSION_HPP
17 #define R_RSESSION_HPP
18 
19 #include <string>
20 
21 #include <boost/function.hpp>
22 
23 #include <shared_core/json/Json.hpp>
24 #include <shared_core/FilePath.hpp>
25 
26 #include <core/r_util/RSessionContext.hpp>
27 
28 #include <R_ext/RStartup.h>
29 #include <r/session/RSessionUtils.hpp>
30 
31 #define kConsoleInputCancel 1
32 #define kConsoleInputEof    2
33 
34 #define EX_CONTINUE                         100
35 #define EX_FORCE                            101
36 #define EX_SUSPEND_RESTART_LAUNCHER_SESSION 102
37 
38 namespace rstudio {
39 namespace core {
40    class Error;
41    class Settings;
42 }
43 }
44 
45 namespace rstudio {
46 namespace r {
47 namespace session {
48 
49 struct RClientMetrics
50 {
RClientMetricsrstudio::r::session::RClientMetrics51    RClientMetrics()
52       : consoleWidth(0), buildConsoleWidth(0), graphicsWidth(0),
53         graphicsHeight(0), devicePixelRatio(1.0)
54    {
55    }
56    int consoleWidth;
57    int buildConsoleWidth;
58    int graphicsWidth;
59    int graphicsHeight;
60    double devicePixelRatio;
61 };
62 
63 struct ROptions
64 {
ROptionsrstudio::r::session::ROptions65    ROptions() :
66          useInternet2(true),
67          rCompatibleGraphicsEngineVersion(14),
68          serverMode(false),
69          autoReloadSource(false),
70          restoreWorkspace(true),
71          saveWorkspace(SA_SAVEASK),
72          disableRProfileOnStart(false),
73          rProfileOnResume(false),
74          restoreEnvironmentOnResume(true),
75          packratEnabled(false),
76          suspendOnIncompleteStatement(false)
77    {
78    }
79    core::FilePath userHomePath;
80    core::FilePath userScratchPath;
81    core::FilePath scopedScratchPath;
82    core::FilePath sessionScratchPath;
83    core::FilePath logPath;
84    core::FilePath startupEnvironmentFilePath;
85    std::string sessionPort;
86    boost::function<core::FilePath()> rEnvironmentDir;
87    boost::function<core::FilePath()> rHistoryDir;
88    boost::function<bool()> alwaysSaveHistory;
89    core::FilePath rSourcePath;
90    std::string rLibsUser;
91    std::string rCRANUrl;
92    std::string rCRANSecondary;
93    std::string runScript;
94    bool useInternet2;
95    int rCompatibleGraphicsEngineVersion;
96    bool serverMode;
97    bool autoReloadSource;
98    bool restoreWorkspace;
99    SA_TYPE saveWorkspace;
100    bool disableRProfileOnStart;
101    bool rProfileOnResume;
102    bool restoreEnvironmentOnResume;
103    core::r_util::SessionScope sessionScope;
104    bool packratEnabled;
105    bool suspendOnIncompleteStatement;
106 };
107 
108 struct RInitInfo
109 {
RInitInforstudio::r::session::RInitInfo110    RInitInfo()
111       : resumed(false)
112    {
113    }
RInitInforstudio::r::session::RInitInfo114    RInitInfo(bool resumed)
115       : resumed(resumed)
116    {
117    }
118    bool resumed;
119 };
120 
121 struct RConsoleInput
122 {
RConsoleInputrstudio::r::session::RConsoleInput123    explicit RConsoleInput()
124       : flags(0)
125    {
126    }
127 
RConsoleInputrstudio::r::session::RConsoleInput128    explicit RConsoleInput(int flags)
129       : flags(flags)
130    {
131    }
132 
RConsoleInputrstudio::r::session::RConsoleInput133    explicit RConsoleInput(const std::string& text,
134                           const std::string& console = "",
135                           int flags = 0)
136       : text(text),
137         console(console),
138         flags(flags)
139    {
140    }
141 
isCancelrstudio::r::session::RConsoleInput142    bool isCancel()
143    {
144       return (flags & kConsoleInputCancel) != 0;
145    }
146 
isEofrstudio::r::session::RConsoleInput147    bool isEof()
148    {
149       return (flags & kConsoleInputEof) != 0;
150    }
151 
152    // typically used for hand-constructed RPC requests
toJsonArrayrstudio::r::session::RConsoleInput153    core::json::Array toJsonArray()
154    {
155       core::json::Array jsonArray;
156       jsonArray.push_back(text);
157       jsonArray.push_back(console);
158       jsonArray.push_back(flags);
159       return jsonArray;
160    }
161 
162    std::string text;
163    std::string console;
164    int flags;
165 };
166 
167 // forward declare DisplayState
168 namespace graphics {
169    struct DisplayState;
170 }
171 
172 // serialization actions
173 extern const int kSerializationActionSaveDefaultWorkspace;
174 extern const int kSerializationActionLoadDefaultWorkspace;
175 extern const int kSerializationActionSuspendSession;
176 extern const int kSerializationActionResumeSession;
177 extern const int kSerializationActionCompleted;
178 
179 struct RSuspendOptions;
180 struct RCallbacks
181 {
182    boost::function<core::Error(const RInitInfo&)> init;
183    boost::function<void()> initComplete;
184    boost::function<bool(const std::string&, bool, RConsoleInput*)> consoleRead;
185    boost::function<void(const std::string&)> browseURL;
186    boost::function<void(const core::FilePath&)> browseFile;
187    boost::function<void(const std::string&)> showHelp;
188    boost::function<void(const std::string&, core::FilePath&, bool)> showFile;
189    boost::function<void(const std::string&, int)> consoleWrite;
190    boost::function<void()> consoleHistoryReset;
191    boost::function<bool(double*, double*)> locator;
192    boost::function<core::FilePath(bool)> chooseFile;
193    boost::function<int(const std::string&)> editFile;
194    boost::function<void(const std::string&)> showMessage;
195    boost::function<void(bool)> busy;
196    boost::function<void(bool)> deferredInit;
197    boost::function<void(const r::session::RSuspendOptions& options)> suspended;
198    boost::function<void()> resumed;
199    boost::function<bool()> handleUnsavedChanges;
200    boost::function<void()> quit;
201    boost::function<void(const std::string&)> suicide;
202    boost::function<void(bool)> cleanup;
203    boost::function<void(int, const core::FilePath&)> serialization;
204    boost::function<void()> runTests;
205 };
206 
207 // run the session
208 core::Error run(const ROptions& options, const RCallbacks& callbacks);
209 
210 // deferred deserialization of the session
211 void ensureDeserialized();
212 
213 // set client metrics
214 void setClientMetrics(const RClientMetrics& metrics);
215 
216 // report a warning to the user and also log it
217 void reportAndLogWarning(const std::string& warning);
218 
219 // suspend/resume
220 bool isSuspendable(const std::string& prompt);
221 bool suspend(bool force, int status, const std::string& ephemeralEnvVars);
222 
223 struct RSuspendOptions
224 {
RSuspendOptionsrstudio::r::session::RSuspendOptions225    RSuspendOptions(int exitStatus)
226       : status(exitStatus)
227    {
228    }
229 
RSuspendOptionsrstudio::r::session::RSuspendOptions230    RSuspendOptions(int exitStatus, const std::string& ephemeral)
231       : status(exitStatus),
232         ephemeralEnvVars(ephemeral)
233    {
234    }
235    int status;
236    bool saveMinimal { false };
237    bool saveWorkspace { false };
238    bool excludePackages { false };
239    std::string ephemeralEnvVars;
240 };
241 void suspendForRestart(const RSuspendOptions& options);
242 
243 // set save action
244 extern const int kSaveActionNoSave;
245 extern const int kSaveActionSave;
246 extern const int kSaveActionAsk;
247 void setSaveAction(int saveAction);
248 
249 // image dirty state
250 void setImageDirty(bool imageDirty);
251 bool imageIsDirty();
252 
253 // check whether there is a browser context active
254 bool browserContextActive();
255 
256 // quit
257 void quit(bool saveWorkspace, int status = EXIT_SUCCESS);
258 
259 } // namespace session
260 } // namespace r
261 } // namespace rstudio
262 
263 #endif // R_RSESSION_HPP
264 
265