-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(tesseratos): add ProjectManager system argument
- Loading branch information
Showing
8 changed files
with
286 additions
and
118 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
#include "manager.hpp" | ||
#include <thread> | ||
|
||
#include <cubos/core/data/fs/file_system.hpp> | ||
#include <cubos/core/data/fs/standard_archive.hpp> | ||
#include <cubos/core/reflection/external/cstring.hpp> | ||
#include <cubos/core/reflection/external/primitives.hpp> | ||
#include <cubos/core/reflection/external/string.hpp> | ||
#include <cubos/core/reflection/traits/constructible.hpp> | ||
#include <cubos/core/reflection/type.hpp> | ||
|
||
using cubos::core::data::FileSystem; | ||
using cubos::core::data::StandardArchive; | ||
using cubos::core::net::Address; | ||
|
||
CUBOS_REFLECT_IMPL(tesseratos::ProjectManager::State) | ||
{ | ||
using namespace cubos::core::reflection; | ||
return Type::create("tesseratos::ProjectManager::State") | ||
.with(ConstructibleTrait::typed<State>().withMoveConstructor().build()); | ||
} | ||
|
||
tesseratos::ProjectManager::ProjectManager(State& state, cubos::engine::Assets& assets, Debugger& debugger) | ||
: mState(state) | ||
, mAssets(assets) | ||
, mDebugger(debugger) | ||
{ | ||
} | ||
|
||
bool tesseratos::ProjectManager::open(std::string projectOSPath, std::string binaryOSPath) | ||
{ | ||
if (projectOSPath.empty()) | ||
{ | ||
CUBOS_ERROR("Project path is empty"); | ||
return false; | ||
} | ||
|
||
this->close(); | ||
|
||
// Prepare the project directory for mounting. | ||
auto archive = std::make_unique<StandardArchive>(projectOSPath, /*isDirectory=*/true, /*readOnly=*/false); | ||
if (!archive->initialized()) | ||
{ | ||
CUBOS_ERROR("Could not open project at {}", projectOSPath); | ||
return false; | ||
} | ||
|
||
if (!FileSystem::mount("/project", std::move(archive))) | ||
{ | ||
CUBOS_ERROR("Could not mount project archive to /project"); | ||
return false; | ||
} | ||
|
||
// Load asset metadata from the project assets directory. | ||
mAssets.loadMeta("/project/assets"); | ||
|
||
// We managed to open the project's directory, store the paths. | ||
mState.mProjectOSPath = std::move(projectOSPath); | ||
mState.mBinaryOSPath = std::move(binaryOSPath); | ||
|
||
// Try to launch the project. | ||
// If we can't, we can still keep the project open, but we won't be able to use its types. | ||
this->launch(); | ||
|
||
return true; | ||
} | ||
|
||
bool tesseratos::ProjectManager::open() const | ||
{ | ||
return !mState.mProjectOSPath.empty(); | ||
} | ||
|
||
void tesseratos::ProjectManager::close() | ||
{ | ||
if (mState.mProjectOSPath.empty()) | ||
{ | ||
return; | ||
} | ||
|
||
this->terminate(); | ||
|
||
// Unload asset metadata from the project. | ||
mAssets.unloadMeta("/project/assets"); | ||
|
||
// Unmount its directory from the virtual file system. | ||
if (!FileSystem::unmount("/project")) | ||
{ | ||
CUBOS_ERROR("Failed to unmount previously open project directory"); | ||
} | ||
|
||
mState.mProjectOSPath.clear(); | ||
} | ||
|
||
bool tesseratos::ProjectManager::launch() | ||
{ | ||
// Stop the binary if it is already running. | ||
this->terminate(); | ||
|
||
if (!mState.mProcess.start(mState.mBinaryOSPath, {"--debug", std::to_string(mState.mPort)})) | ||
{ | ||
CUBOS_ERROR("Could not start project's process at {}", mState.mBinaryOSPath); | ||
return false; | ||
} | ||
|
||
// Try to connect to the child process's debugger. | ||
for (int i = 1, sleep = 100; i <= 3; ++i, sleep *= 2) | ||
{ | ||
if (i > 0) | ||
{ | ||
CUBOS_WARN("CCould not connect to project's process debugger in try {}, retrying in {} ms", i - 1, sleep); | ||
std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); | ||
} | ||
|
||
if (mDebugger.connect(Address::LocalHost, mState.mPort)) | ||
{ | ||
CUBOS_INFO("Successfully connected to project's process debugger in try {}", i); | ||
break; | ||
} | ||
} | ||
|
||
// Check if we successfully connected to the child process's debugger. | ||
// If we didn't, kill the child process. | ||
if (!mDebugger.isConnected()) | ||
{ | ||
CUBOS_ERROR("Could not connect to the project's process debugger, terminating the process"); | ||
mState.mProcess.kill(); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
void tesseratos::ProjectManager::terminate() | ||
{ | ||
if (mDebugger.isConnected()) | ||
{ | ||
mDebugger.close(); // Issue a close command to the process' debugger. | ||
} | ||
else | ||
{ | ||
mState.mProcess.kill(); | ||
} | ||
|
||
mState.mProcess.wait(); // Wait for the process to finish. | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
/// @file | ||
/// @brief System argument @ref tesseratos::ProjectManager. | ||
/// @ingroup tesseratos-debugger-plugin | ||
|
||
#pragma once | ||
|
||
#include <string> | ||
|
||
#include <cubos/core/ecs/system/fetcher.hpp> | ||
#include <cubos/core/thread/process.hpp> | ||
|
||
#include <cubos/engine/assets/plugin.hpp> | ||
|
||
#include "../debugger/debugger.hpp" | ||
|
||
namespace tesseratos | ||
{ | ||
/// @brief System argument which can be used to manage the currently loaded project. | ||
class ProjectManager | ||
{ | ||
public: | ||
CUBOS_REFLECT; | ||
|
||
/// @brief Resource which holds the state of the project manager. | ||
class State; | ||
|
||
/// @brief Constructs. | ||
/// @param state State of the project manager. | ||
/// @param assets Asset manager. | ||
/// @param debugger Debugger. | ||
ProjectManager(State& state, cubos::engine::Assets& assets, Debugger& debugger); | ||
|
||
/// @brief Opens a project directory. | ||
/// | ||
/// The given project directory is mounted in the /project directory in the virtual file system. | ||
/// Unmounts any previously opened project directory. | ||
/// | ||
/// @param projectOSPath Project's directory path in the operating system. | ||
/// @param binaryOSPath Project's binary directory path in the operating system. | ||
/// @return Whether the project could be opened successfully. | ||
bool open(std::string projectOSPath, std::string binaryOSPath); | ||
|
||
/// @brief Checks whether a project is currently open. | ||
/// @return Whether a project is currently open. | ||
bool open() const; | ||
|
||
/// @brief Closes the currently open project. | ||
void close(); | ||
|
||
/// @brief Launches the project's binary and attaches the debugger. | ||
/// | ||
/// If the binary is already running, it is stopped first. | ||
/// | ||
/// @return Whether the project could be launched successfully. | ||
bool launch(); | ||
|
||
/// @brief Stops the project's binary. | ||
void terminate(); | ||
|
||
private: | ||
State& mState; | ||
cubos::engine::Assets& mAssets; | ||
Debugger& mDebugger; | ||
}; | ||
|
||
class ProjectManager::State | ||
{ | ||
public: | ||
CUBOS_REFLECT; | ||
|
||
/// @brief Default constructs. | ||
State() = default; | ||
|
||
private: | ||
friend ProjectManager; | ||
|
||
std::string mProjectOSPath{}; | ||
std::string mBinaryOSPath{}; | ||
cubos::core::thread::Process mProcess{}; | ||
uint16_t mPort{9335}; | ||
}; | ||
} // namespace tesseratos | ||
|
||
namespace cubos::core::ecs | ||
{ | ||
template <> | ||
class SystemFetcher<tesseratos::ProjectManager> | ||
{ | ||
public: | ||
static inline constexpr bool ConsumesOptions = false; | ||
|
||
SystemFetcher<tesseratos::ProjectManager::State&> state; | ||
SystemFetcher<cubos::engine::Assets&> assets; | ||
SystemFetcher<tesseratos::Debugger&> debugger; | ||
|
||
SystemFetcher(World& world, const SystemOptions& options) | ||
: state{world, options} | ||
, assets{world, options} | ||
, debugger{world, options} | ||
{ | ||
} | ||
|
||
void analyze(SystemAccess& access) const | ||
{ | ||
state.analyze(access); | ||
assets.analyze(access); | ||
debugger.analyze(access); | ||
} | ||
|
||
tesseratos::ProjectManager fetch(const SystemContext& ctx) | ||
{ | ||
return {state.fetch(ctx), assets.fetch(ctx), debugger.fetch(ctx)}; | ||
} | ||
}; | ||
} // namespace cubos::core::ecs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.