Skip to content

Commit

Permalink
chore(refactor): Code readability, put Client/Server main on top
Browse files Browse the repository at this point in the history
  • Loading branch information
whisperity committed May 7, 2022
1 parent 7597398 commit b43eaf0
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 146 deletions.
7 changes: 7 additions & 0 deletions include/implementation/monomux/client/Main.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ struct Options
std::optional<Client>
connect(Options& Opts, bool Block, std::string* FailureReason);

/// Attempts to make the \p Client fully featured with a \b Data connection,
/// capable of actually exchanging user-specific information with the server.
///
/// \param FailureReason If given, after an unsuccessful connection, a
/// human-readable reason for the failure will be written to.
bool makeWholeWithData(Client& Client, std::string* FailureReason);

/// Executes the Monomux Client logic.
///
/// \returns \p ExitCode
Expand Down
213 changes: 114 additions & 99 deletions src/client/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,60 +111,29 @@ connect(Options& Opts, bool Block, std::string* FailureReason)
return C;
}

static constexpr char TerminalObjName[] = "Terminal";
static constexpr char MasterAborterName[] = "Master-Aborter";

// NOLINTNEXTLINE(cert-err58-cpp)
static auto OriginalLogLevel =
makeLazy([]() -> log::Severity { return log::Logger::get().getLimit(); });

/// Handler for \p SIGWINCH (window size change) events produces by the terminal
/// the program is running in.
static void windowSizeChange(SignalHandling::Signal /* SigNum */,
::siginfo_t* /* Info */,
const SignalHandling* Handling)
bool makeWholeWithData(Client& Client, std::string* FailureReason)
{
const volatile auto* Term =
std::any_cast<Terminal*>(Handling->getObject(TerminalObjName));
if (!Term)
return;
(*Term)->notifySizeChanged();
}

/// Custom handler for \p SIGABRT. This is even more custom than the handler in
/// the global \p main() as it deals with resetting the terminal to sensible
/// defaults first.
static void coreDumped(SignalHandling::Signal SigNum,
::siginfo_t* Info,
const SignalHandling* Handling)
{
// Reset the loglevel so all messages that might appear appear as needed.
log::Logger::get().setLimit(OriginalLogLevel.get());

// Reset the terminal so we don't get weird output if the client crashed in
// the middle of a formatting sequence.
const volatile auto* Term =
std::any_cast<Terminal*>(Handling->getObject(TerminalObjName));
if (Term)
static constexpr std::size_t MaxHandshakeTries = 16;
unsigned short HandshakeCounter = 0;
while (!Client.handshake(FailureReason))
{
(*Term)->disengage();
(*Term)->releaseClient();
}
++HandshakeCounter;
if (HandshakeCounter == MaxHandshakeTries)
{
if (FailureReason)
FailureReason->insert(
0, "Failed to establish full connection after enough retries. ");
return false;
}

// Fallback to the master handler that main.cpp should've installed.
const auto* MasterAborter =
std::any_cast<std::function<SignalHandling::SignalCallback>>(
Handling->getObject(MasterAborterName));
if (MasterAborter)
(*MasterAborter)(SigNum, Info, Handling);
else
{
LOG(fatal) << "In Client, " << SignalHandling::signalName(SigNum)
<< " FATAL SIGNAL received, but local handler did not find the "
"appropriate master one.";
LOG(warn) << "Establishing full connection failed:\n\t" << FailureReason;
std::this_thread::sleep_for(std::chrono::seconds(1));
}

return true;
}


namespace
{

Expand All @@ -183,22 +152,33 @@ struct SessionSelectionResult
SessionMode Mode;
};

} // namespace
SessionSelectionResult selectSession(const std::vector<SessionData>& Sessions,
const std::string& ToCreateSessionName);
SessionSelectionResult selectSession(const std::string& ClientID,
const std::string& DefaultProgram,
const std::vector<SessionData>& Sessions,
const std::string& ToCreateSessionName,
bool ListSessions,
bool Interactive);
ExitCode mainForControlClient(Options& Opts);
ExitCode handleSessionCreateOrAttach(Options& Opts);
int handleClientExitStatus(const Client& Client);

void windowSizeChange(SignalHandling::Signal SigNum,
::siginfo_t* Info,
const SignalHandling* Handling);
void coreDumped(SignalHandling::Signal SigNum,
::siginfo_t* Info,
const SignalHandling* Handling);

static SessionSelectionResult
selectSession(const std::vector<SessionData>& Sessions,
const std::string& ToCreateSessionName);
static SessionSelectionResult
selectSession(const std::string& ClientID,
const std::string& DefaultProgram,
const std::vector<SessionData>& Sessions,
const std::string& ToCreateSessionName,
bool ListSessions,
bool Interactive);
static ExitCode mainForControlClient(Options& Opts);
static bool handshakeDataConnection(Client& Client);
static ExitCode handleSessionCreateOrAttach(Options& Opts);
static int handleClientExitStatus(const Client& Client);
// NOLINTNEXTLINE(cert-err58-cpp)
auto OriginalLogLevel =
makeLazy([]() -> log::Severity { return log::Logger::get().getLimit(); });

constexpr char TerminalObjName[] = "Terminal";
constexpr char MasterAborterName[] = "Master-Aborter";

} // namespace

int main(Options& Opts)
{
Expand Down Expand Up @@ -297,9 +277,11 @@ int main(Options& Opts)
return handleClientExitStatus(Client);
}

static SessionSelectionResult
selectSession(const std::vector<SessionData>& Sessions,
const std::string& ToCreateSessionName)
namespace
{

SessionSelectionResult selectSession(const std::vector<SessionData>& Sessions,
const std::string& ToCreateSessionName)
{
if (Sessions.empty())
{
Expand Down Expand Up @@ -332,13 +314,12 @@ selectSession(const std::vector<SessionData>& Sessions,
unreachable("Previous decisions should have returned.");
}

static SessionSelectionResult
selectSession(const std::string& ClientID,
const std::string& DefaultProgram,
const std::vector<SessionData>& Sessions,
const std::string& ToCreateSessionName,
bool UserWantsOnlyListSessions,
bool UserWantsInteractive)
SessionSelectionResult selectSession(const std::string& ClientID,
const std::string& DefaultProgram,
const std::vector<SessionData>& Sessions,
const std::string& ToCreateSessionName,
bool UserWantsOnlyListSessions,
bool UserWantsInteractive)
{
const bool NeedsInteractive =
UserWantsInteractive || UserWantsOnlyListSessions || Sessions.size() >= 2;
Expand Down Expand Up @@ -400,7 +381,7 @@ selectSession(const std::string& ClientID,
}

/// Handles operations through a \p ControlClient -only connection.
static ExitCode mainForControlClient(Options& Opts)
ExitCode mainForControlClient(Options& Opts)
{
if (!Opts.SessionData)
Opts.SessionData = MonomuxSession::loadFromEnv();
Expand All @@ -427,30 +408,8 @@ static ExitCode mainForControlClient(Options& Opts)
return EXIT_Success;
}

/// Elevates the \p Client to have a full-fledged \b Data connection with the
/// server.
static bool handshakeDataConnection(Client& Client)
{
std::string FailureReason;
static constexpr std::size_t MaxHandshakeTries = 16;
unsigned short HandshakeCounter = 0;
while (!Client.handshake(&FailureReason))
{
++HandshakeCounter;
if (HandshakeCounter == MaxHandshakeTries)
{
LOG(fatal) << "Failed to establish full connection after enough retries.";
return false;
}

LOG(warn) << "Establishing full connection failed:\n\t" << FailureReason;
std::this_thread::sleep_for(std::chrono::seconds(1));
}

return true;
}

static ExitCode handleSessionCreateOrAttach(Options& Opts)
ExitCode handleSessionCreateOrAttach(Options& Opts)
{
Client& Client = *Opts.Connection;

Expand Down Expand Up @@ -505,7 +464,14 @@ static ExitCode handleSessionCreateOrAttach(Options& Opts)
}
if (SessionAction.Mode == SessionSelectionResult::Attach)
{
handshakeDataConnection(Client);
{
std::string DataFailure;
if (!makeWholeWithData(Client, &DataFailure))
{
LOG(fatal) << DataFailure;
return EXIT_SystemError;
}
}

LOG(debug) << "Attaching to \"" << SessionAction.SessionName << "\"...";
bool Attached = Client.requestAttach(std::move(SessionAction.SessionName));
Expand All @@ -520,7 +486,7 @@ static ExitCode handleSessionCreateOrAttach(Options& Opts)
return EXIT_Success;
}

static int handleClientExitStatus(const Client& Client)
int handleClientExitStatus(const Client& Client)
{
switch (Client.exitReason())
{
Expand Down Expand Up @@ -557,4 +523,53 @@ static int handleClientExitStatus(const Client& Client)
return EXIT_Success;
}

/// Handler for \p SIGWINCH (window size change) events produces by the terminal
/// the program is running in.
void windowSizeChange(SignalHandling::Signal /* SigNum */,
::siginfo_t* /* Info */,
const SignalHandling* Handling)
{
const volatile auto* Term =
std::any_cast<Terminal*>(Handling->getObject(TerminalObjName));
if (!Term)
return;
(*Term)->notifySizeChanged();
}

/// Custom handler for \p SIGABRT. This is even more custom than the handler in
/// the global \p main() as it deals with resetting the terminal to sensible
/// defaults first.
void coreDumped(SignalHandling::Signal SigNum,
::siginfo_t* Info,
const SignalHandling* Handling)
{
// Reset the loglevel so all messages that might appear appear as needed.
log::Logger::get().setLimit(OriginalLogLevel.get());

// Reset the terminal so we don't get weird output if the client crashed in
// the middle of a formatting sequence.
const volatile auto* Term =
std::any_cast<Terminal*>(Handling->getObject(TerminalObjName));
if (Term)
{
(*Term)->disengage();
(*Term)->releaseClient();
}

// Fallback to the master handler that main.cpp should've installed.
const auto* MasterAborter =
std::any_cast<std::function<SignalHandling::SignalCallback>>(
Handling->getObject(MasterAborterName));
if (MasterAborter)
(*MasterAborter)(SigNum, Info, Handling);
else
{
LOG(fatal) << "In Client, " << SignalHandling::signalName(SigNum)
<< " FATAL SIGNAL received, but local handler did not find the "
"appropriate master one.";
}
}

} // namespace

} // namespace monomux::client
5 changes: 3 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ void printHelp();
void printVersion();
void printFeatures();
void coreDumped(SignalHandling::Signal SigNum,
::siginfo_t* /* Info */,
::siginfo_t* Info,
const SignalHandling* Handling);

} // namespace
Expand Down Expand Up @@ -452,7 +452,8 @@ Client options:
monomux -n session -- /bin/bash --no-rc
-n NAME, --name NAME - Name of the remote session to attach to or
create. (Defaults to: "default".)
create. (Defaults to an automatically
generated value.)
-l, --list - List the sessions that are running on the
server listening on the socket given to
'--socket', but do not attach or configure
Expand Down
Loading

0 comments on commit b43eaf0

Please sign in to comment.