1 /*
2 * SessionPersistentState.cpp
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 #include <session/SessionPersistentState.hpp>
17
18 #include <core/Log.hpp>
19 #include <shared_core/Error.hpp>
20 #include <shared_core/FilePath.hpp>
21 #include <core/FileSerializer.hpp>
22 #include <core/system/System.hpp>
23
24 #include <session/SessionOptions.hpp>
25 #include <session/SessionModuleContext.hpp>
26
27 #include "session-config.h"
28
29 #ifdef RSTUDIO_SERVER
30 #include <server_core/UrlPorts.hpp>
31 #endif
32
33 using namespace rstudio::core;
34
35 namespace rstudio {
36 namespace session {
37
38 namespace {
39 const char * const kActiveClientId = "active-client-id";
40 const char * const kAbend = "abend";
41 }
42
persistentState()43 PersistentState& persistentState()
44 {
45 static PersistentState instance;
46 return instance;
47 }
48
initialize()49 Error PersistentState::initialize()
50 {
51 serverMode_ = (session::options().programMode() ==
52 kSessionProgramModeServer);
53
54 // always the same so that we can supporrt a restart of
55 // the session without reloading the client page
56 desktopClientId_ = "33e600bb-c1b1-46bf-b562-ab5cba070b0e";
57
58 // scoped/project settings
59 FilePath scratchPath = module_context::scopedScratchPath();
60 FilePath statePath = scratchPath.completePath("persistent-state");
61 Error error = settings_.initialize(statePath);
62 if (error)
63 return error;
64
65 // session settings
66 scratchPath = module_context::sessionScratchPath();
67 statePath = scratchPath.completePath("session-persistent-state");
68 return sessionSettings_.initialize(statePath);
69 }
70
activeClientId()71 std::string PersistentState::activeClientId()
72 {
73 if (serverMode_)
74 {
75 std::string activeClientId = sessionSettings_.get(kActiveClientId);
76 if (!activeClientId.empty())
77 return activeClientId;
78 else
79 return newActiveClientId();
80 }
81 else
82 {
83 return desktopClientId_;
84 }
85 }
86
newActiveClientId()87 std::string PersistentState::newActiveClientId()
88 {
89 if (serverMode_)
90 {
91 std::string newId = core::system::generateUuid();
92 sessionSettings_.set(kActiveClientId, newId);
93 return newId;
94 }
95 else
96 {
97 return desktopClientId_;
98 }
99 }
100
activeClientUrl() const101 std::string PersistentState::activeClientUrl() const
102 {
103 return settings_.get("activeClientUrl", "");
104 }
105
setActiveClientUrl(const std::string & url)106 void PersistentState::setActiveClientUrl(const std::string& url)
107 {
108 settings_.set("activeClientUrl", url);
109 }
110
111 // abend tracking only applies to server mode
112
hadAbend()113 bool PersistentState::hadAbend()
114 {
115 if (serverMode_)
116 {
117 return sessionSettings_.getInt(kAbend, false);
118 }
119 else
120 {
121 return false;
122 }
123 }
124
setAbend(bool abend)125 void PersistentState::setAbend(bool abend)
126 {
127 if (serverMode_)
128 {
129 sessionSettings_.set(kAbend, abend);
130 }
131 }
132
activeEnvironmentName() const133 std::string PersistentState::activeEnvironmentName() const
134 {
135 return settings_.get("activeEnvironmentName", "R_GlobalEnv");
136 }
137
setActiveEnvironmentName(std::string environmentName)138 void PersistentState::setActiveEnvironmentName(std::string environmentName)
139 {
140 settings_.set("activeEnvironmentName", environmentName);
141 }
142
143
portToken() const144 std::string PersistentState::portToken() const
145 {
146 return settings_.get("portToken",
147 #ifdef RSTUDIO_SERVER
148 // on RStudio Server, we have a fallback default so that we're guaranteed to have a port token to
149 // work with (better a predictable obfuscated value than a raw or busted one)
150 kDefaultPortToken
151 #else
152 // Desktop doesn't use port tokens
153 ""
154 #endif
155 );
156 }
157
setPortToken(const std::string & token)158 void PersistentState::setPortToken(const std::string& token)
159 {
160 settings_.set("portToken", token);
161 }
162
getStoredHash(const std::string & hashName) const163 std::string PersistentState::getStoredHash(const std::string& hashName) const
164 {
165 return settings_.get(hashName + "Hash", "");
166 }
167
setStoredHash(const std::string & hashName,const std::string & hashValue)168 void PersistentState::setStoredHash(const std::string& hashName,
169 const std::string& hashValue)
170 {
171 settings_.set(hashName + "Hash", hashValue);
172 }
173
environmentMonitoring() const174 bool PersistentState::environmentMonitoring() const
175 {
176 return settings_.getBool("environmentMonitoring", true);
177 }
178
setEnvironmentMonitoring(bool monitoring)179 void PersistentState::setEnvironmentMonitoring(bool monitoring)
180 {
181 return settings_.set("environmentMonitoring", monitoring);
182 }
183
reusedStandalonePort() const184 std::string PersistentState::reusedStandalonePort() const
185 {
186 if (session::options().getBoolOverlayOption(kLauncherSessionOption))
187 return sessionSettings_.get("reusedStandalonePort", "");
188
189 return std::string();
190 }
191
setReusedStandalonePort(const std::string & port)192 void PersistentState::setReusedStandalonePort(const std::string& port)
193 {
194 if (session::options().getBoolOverlayOption(kLauncherSessionOption))
195 sessionSettings_.set("reusedStandalonePort", port);
196 }
197
reusedSessionProxyPort() const198 std::string PersistentState::reusedSessionProxyPort() const
199 {
200 if (session::options().getBoolOverlayOption(kLauncherSessionOption))
201 return sessionSettings_.get("reusedSessionProxyPort", "");
202
203 return std::string();
204 }
205
setReusedSessionProxyPort(const std::string & port)206 void PersistentState::setReusedSessionProxyPort(const std::string& port)
207 {
208 if (session::options().getBoolOverlayOption(kLauncherSessionOption))
209 sessionSettings_.set("reusedSessionProxyPort", port);
210 }
211
212 } // namespace session
213 } // namespace rstudio
214