1 /* 2 * SessionConsoleProcessInfo.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 #ifndef SESSION_CONSOLE_PROCESS_INFO_HPP 16 #define SESSION_CONSOLE_PROCESS_INFO_HPP 17 18 #include <boost/circular_buffer.hpp> 19 #include <boost/enable_shared_from_this.hpp> 20 21 #include <shared_core/FilePath.hpp> 22 #include <core/json/JsonRpc.hpp> 23 #include <core/system/Process.hpp> 24 #include <core/system/Types.hpp> 25 26 #include <session/SessionTerminalShell.hpp> 27 28 namespace rstudio { 29 namespace core { 30 class Error; 31 } 32 } 33 34 namespace rstudio { 35 namespace session { 36 namespace console_process { 37 38 enum InteractionMode 39 { 40 InteractionNever = 0, 41 InteractionPossible = 1, 42 InteractionAlways = 2 43 }; 44 45 enum ChannelMode 46 { 47 Rpc = 0, 48 Websocket = 1, 49 }; 50 51 enum AutoCloseMode 52 { 53 DefaultAutoClose = 0, // obey user preference 54 AlwaysAutoClose = 1, // always auto-close 55 NeverAutoClose = 2, // never auto-close 56 CleanExitAutoClose = 3, // auto-close only if shell returned zero exit code 57 }; 58 59 enum SerializationMode 60 { 61 ClientSerialization = 0, // serialize for front-end client 62 PersistentSerialization = 1 // serialize for persistent storage 63 }; 64 65 extern const int kDefaultMaxOutputLines; 66 extern const int kDefaultTerminalMaxOutputLines; 67 extern const int kNoTerminal; 68 extern const int kNewTerminal; 69 extern const size_t kOutputBufferSize; 70 71 // ConsoleProcess metadata that is persisted, and sent to the client on 72 // create/reconnect 73 class ConsoleProcessInfo : boost::noncopyable, 74 public boost::enable_shared_from_this<ConsoleProcessInfo> 75 { 76 private: 77 // This constructor is only for resurrecting orphaned processes (i.e. for 78 // suspend/resume scenarios) 79 ConsoleProcessInfo(); 80 81 public: 82 // constructor for interactive terminals 83 ConsoleProcessInfo( 84 const std::string& caption, 85 const std::string& title, 86 const std::string& handle, 87 int terminalSequence, 88 TerminalShell::ShellType shellType, 89 bool altBufferActive, 90 const core::FilePath& cwd, 91 int cols, int rows, bool zombie, bool trackEnv); 92 93 // constructor for non-terminals 94 ConsoleProcessInfo( 95 const std::string& caption, 96 InteractionMode mode, 97 int maxOutputLines = kDefaultMaxOutputLines); 98 99 virtual ~ConsoleProcessInfo() = default; 100 101 // Caption is shown on terminal tabs, e.g. Terminal 1 setCaption(std::string & caption)102 void setCaption(std::string& caption) { caption_ = caption; } getCaption() const103 std::string getCaption() const { return caption_; } 104 105 // Title is set by terminal escape sequence, typically to show current dir setTitle(std::string & title)106 void setTitle(std::string& title) { title_ = title; } getTitle() const107 std::string getTitle() const { return title_; } 108 109 // Handle client uses to refer to this process 110 void ensureHandle(); getHandle() const111 std::string getHandle() const { return handle_; } 112 113 // Sequence number of the associated terminal; used to control display 114 // order of terminal tabs; constant 'kNoTerminal' indicates a non-terminal setTerminalSequence(int sequence)115 void setTerminalSequence(int sequence) { terminalSequence_ = sequence; } getTerminalSequence() const116 int getTerminalSequence() const { return terminalSequence_; } 117 118 // Whether a ConsoleProcess object should start a new process on resume after 119 // its process has been killed by a suspend. setAllowRestart(bool allowRestart)120 void setAllowRestart(bool allowRestart) { allowRestart_ = allowRestart; } getAllowRestart() const121 bool getAllowRestart() const { return allowRestart_; } 122 setInteractionMode(InteractionMode mode)123 void setInteractionMode(InteractionMode mode) { interactionMode_ = mode; } getInteractionMode() const124 InteractionMode getInteractionMode() const { return interactionMode_; } 125 setMaxOutputLines(int maxOutputLines)126 void setMaxOutputLines(int maxOutputLines) { maxOutputLines_ = maxOutputLines; } getMaxOutputLines() const127 int getMaxOutputLines() const { return maxOutputLines_; } 128 setShowOnOutput(bool showOnOutput)129 void setShowOnOutput(bool showOnOutput) { showOnOutput_ = showOnOutput; } getShowOnOutput() const130 bool getShowOnOutput() const { return showOnOutput_; } 131 132 // Buffer output in case client disconnects/reconnects and needs 133 // to recover some history. 134 void appendToOutputBuffer(const std::string &str); 135 void appendToOutputBuffer(char ch); 136 std::string bufferedOutput() const; 137 std::string getSavedBufferChunk(int chunk, bool* pMoreAvailable) const; 138 std::string getFullSavedBuffer() const; 139 int getBufferLineCount() const; 140 void deleteLogFile(bool lastLineOnly = false) const; 141 void deleteEnvFile() const; 142 void saveConsoleEnvironment(const core::system::Options& environment); 143 144 // Has the process exited, and what was the exit code? 145 void setExitCode(int exitCode); getExitCode() const146 boost::optional<int> getExitCode() const { return exitCode_; } 147 void resetExitCode(); 148 149 // Does this process have child processes? setHasChildProcs(bool hasChildProcs)150 void setHasChildProcs(bool hasChildProcs) { childProcs_ = hasChildProcs; } getHasChildProcs() const151 bool getHasChildProcs() const { return childProcs_; } 152 153 // What type of shell is this child process running in? getShellType() const154 TerminalShell::ShellType getShellType() const { return shellType_; } setShellType(TerminalShell::ShellType type)155 void setShellType(TerminalShell::ShellType type) { shellType_ = type; } 156 157 // Type of channel for communicating input/output with client getChannelMode() const158 ChannelMode getChannelMode() const { return channelMode_; } 159 160 // Mode-dependent identifier for channel getChannelId() const161 std::string getChannelId() const { return channelId_; } 162 setChannelMode(ChannelMode mode,const std::string & channelId)163 void setChannelMode(ChannelMode mode, const std::string& channelId) 164 { 165 channelMode_ = mode; 166 channelId_ = channelId; 167 } 168 169 // Is terminal showing alt-buffer (a full-screen ncurses program)? setAltBufferActive(bool altBufferActive)170 void setAltBufferActive(bool altBufferActive) { altBufferActive_ = altBufferActive; } getAltBufferActive() const171 bool getAltBufferActive() const { return altBufferActive_; } 172 173 // Last-known current working directory setCwd(const core::FilePath & cwd)174 void setCwd(const core::FilePath& cwd) { cwd_ = cwd; } getCwd() const175 core::FilePath getCwd() const { return cwd_; } 176 177 // Last-known terminal dimensions setCols(int cols)178 void setCols(int cols) { cols_ = cols; } setRows(int rows)179 void setRows(int rows) { rows_ = rows; } getCols() const180 int getCols() const { return cols_; } getRows() const181 int getRows() const { return rows_; } 182 183 // Was terminal session restarted? setRestarted(bool restarted)184 void setRestarted(bool restarted) { restarted_ = restarted; } getRestarted() const185 bool getRestarted() const { return restarted_; } 186 187 // Close terminal session after process exits? setAutoClose(AutoCloseMode autoClose)188 void setAutoClose(AutoCloseMode autoClose) { autoClose_ = autoClose; } getAutoClose() const189 AutoCloseMode getAutoClose() const { return autoClose_; } 190 191 // Is terminal session a zombie (process exited but keeping buffer) setZombie(bool zombie)192 void setZombie(bool zombie) { zombie_ = zombie; } getZombie() const193 bool getZombie() const { return zombie_; } 194 195 // Track terminal session's environment? setTrackEnv(bool trackEnv)196 void setTrackEnv(bool trackEnv) { trackEnv_ = trackEnv; } getTrackEnv() const197 bool getTrackEnv() const { return trackEnv_; } 198 199 core::json::Object toJson(SerializationMode serialMode) const; 200 static boost::shared_ptr<ConsoleProcessInfo> fromJson(const core::json::Object& obj); 201 202 static std::string loadConsoleProcessMetadata(); 203 static void deleteOrphanedLogs(bool (*validHandle)(const std::string&)); 204 static void saveConsoleProcesses(const std::string& metadata); 205 static void loadConsoleEnvironment(const std::string& handle, core::system::Options* pEnv); 206 207 static AutoCloseMode closeModeFromPref(std::string prefValue); 208 209 private: 210 std::string caption_; 211 std::string title_; 212 std::string handle_; 213 int terminalSequence_ = kNoTerminal; 214 bool allowRestart_ = false; 215 InteractionMode interactionMode_ = InteractionNever; 216 int maxOutputLines_ = kDefaultMaxOutputLines; 217 bool showOnOutput_ = false; 218 boost::circular_buffer<char> outputBuffer_ {kOutputBufferSize}; 219 boost::optional<int> exitCode_; 220 #ifdef _WIN32 221 bool childProcs_ = false; // child process detection not supported on Windows 222 #else 223 bool childProcs_ = true; 224 #endif 225 bool altBufferActive_ = false; 226 TerminalShell::ShellType shellType_ = TerminalShell::ShellType::Default; 227 ChannelMode channelMode_ = Rpc; 228 std::string channelId_; 229 core::FilePath cwd_; 230 int cols_ = core::system::kDefaultCols; 231 int rows_ = core::system::kDefaultRows; 232 bool restarted_ = false; 233 AutoCloseMode autoClose_ = DefaultAutoClose; 234 bool zombie_ = false; 235 bool trackEnv_ = false; 236 }; 237 238 } // namespace console_process 239 } // namespace session 240 } // namespace rstudio 241 242 #endif // SESSION_CONSOLE_PROCESS_INFO_HPP 243